/src/ghostpdl/psi/zmath.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Mathematical operators */ |
18 | | #include "math_.h" |
19 | | #include "ghost.h" |
20 | | #include "gxfarith.h" |
21 | | #include "oper.h" |
22 | | #include "store.h" |
23 | | |
24 | | /* |
25 | | * Many of the procedures in this file are public only so they can be |
26 | | * called from the FunctionType 4 interpreter (zfunc4.c). |
27 | | */ |
28 | | |
29 | | /* |
30 | | * Define the current state of random number generator for operators. We |
31 | | * have to implement this ourselves because the Unix rand doesn't provide |
32 | | * anything equivalent to rrand. Note that the value always lies in the |
33 | | * range [0..0x7ffffffe], even if longs are longer than 32 bits. |
34 | | * |
35 | | * The state must be public so that context switching can save and |
36 | | * restore it. (Even though the Red Book doesn't mention this, |
37 | | * we verified with Adobe that this is the case.) |
38 | | */ |
39 | 3.95M | #define zrand_state (i_ctx_p->rand_state) |
40 | | |
41 | | /* Initialize the random number generator. */ |
42 | | const long rand_state_initial = 1; |
43 | | |
44 | | /****** NOTE: none of these operators currently ******/ |
45 | | /****** check for floating over- or underflow. ******/ |
46 | | |
47 | | /* <num> sqrt <real> */ |
48 | | int |
49 | | zsqrt(i_ctx_t *i_ctx_p) |
50 | 621k | { |
51 | 621k | os_ptr op = osp; |
52 | 621k | double num; |
53 | 621k | int code = real_param(op, &num); |
54 | | |
55 | 621k | if (code < 0) |
56 | 11 | return code; |
57 | 621k | if (num < 0.0) |
58 | 7 | return_error(gs_error_rangecheck); |
59 | 621k | make_real(op, sqrt(num)); |
60 | 621k | return 0; |
61 | 621k | } |
62 | | |
63 | | /* <num> arccos <real> */ |
64 | | static int |
65 | | zarccos(i_ctx_t *i_ctx_p) |
66 | 0 | { |
67 | 0 | os_ptr op = osp; |
68 | 0 | double num, result; |
69 | 0 | int code = real_param(op, &num); |
70 | |
|
71 | 0 | if (code < 0) |
72 | 0 | return code; |
73 | 0 | result = acos(num) * radians_to_degrees; |
74 | 0 | make_real(op, result); |
75 | 0 | return 0; |
76 | 0 | } |
77 | | |
78 | | /* <num> arcsin <real> */ |
79 | | static int |
80 | | zarcsin(i_ctx_t *i_ctx_p) |
81 | 0 | { |
82 | 0 | os_ptr op = osp; |
83 | 0 | double num, result; |
84 | 0 | int code = real_param(op, &num); |
85 | |
|
86 | 0 | if (code < 0) |
87 | 0 | return code; |
88 | 0 | result = asin(num) * radians_to_degrees; |
89 | 0 | make_real(op, result); |
90 | 0 | return 0; |
91 | 0 | } |
92 | | |
93 | | /* <num> <denom> atan <real> */ |
94 | | int |
95 | | zatan(i_ctx_t *i_ctx_p) |
96 | 1.55k | { |
97 | 1.55k | os_ptr op = osp; |
98 | 1.55k | double args[2]; |
99 | 1.55k | double result; |
100 | 1.55k | int code = num_params(op, 2, args); |
101 | | |
102 | 1.55k | if (code < 0) |
103 | 14 | return code; |
104 | 1.54k | code = gs_atan2_degrees(args[0], args[1], &result); |
105 | 1.54k | if (code < 0) |
106 | 1 | return code; |
107 | 1.54k | make_real(op - 1, result); |
108 | 1.54k | pop(1); |
109 | 1.54k | return 0; |
110 | 1.54k | } |
111 | | |
112 | | /* <num> cos <real> */ |
113 | | int |
114 | | zcos(i_ctx_t *i_ctx_p) |
115 | 32.1M | { |
116 | 32.1M | os_ptr op = osp; |
117 | 32.1M | double angle; |
118 | 32.1M | int code = real_param(op, &angle); |
119 | | |
120 | 32.1M | if (code < 0) |
121 | 7 | return code; |
122 | 32.1M | make_real(op, gs_cos_degrees(angle)); |
123 | 32.1M | return 0; |
124 | 32.1M | } |
125 | | |
126 | | /* <num> sin <real> */ |
127 | | int |
128 | | zsin(i_ctx_t *i_ctx_p) |
129 | 55.1k | { |
130 | 55.1k | os_ptr op = osp; |
131 | 55.1k | double angle; |
132 | 55.1k | int code = real_param(op, &angle); |
133 | | |
134 | 55.1k | if (code < 0) |
135 | 19 | return code; |
136 | 55.1k | make_real(op, gs_sin_degrees(angle)); |
137 | 55.1k | return 0; |
138 | 55.1k | } |
139 | | |
140 | | /* <base> <exponent> exp <real> */ |
141 | | int |
142 | | zexp(i_ctx_t *i_ctx_p) |
143 | 6.79M | { |
144 | 6.79M | os_ptr op = osp; |
145 | 6.79M | double args[2]; |
146 | 6.79M | double result; |
147 | 6.79M | double ipart; |
148 | 6.79M | int code = num_params(op, 2, args); |
149 | | |
150 | 6.79M | if (code < 0) |
151 | 8 | return code; |
152 | 6.79M | if (args[0] == 0.0 && args[1] < 0) |
153 | 0 | return_error(gs_error_undefinedresult); |
154 | 6.79M | if (args[0] < 0.0 && modf(args[1], &ipart) != 0.0) |
155 | 0 | return_error(gs_error_undefinedresult); |
156 | 6.79M | if (args[0] == 0.0 && args[1] == 0.0) |
157 | 2 | result = 1.0; /* match Adobe; can't rely on C library */ |
158 | 6.79M | else |
159 | 6.79M | result = pow(args[0], args[1]); |
160 | 6.79M | #ifdef HAVE_ISINF |
161 | 6.79M | if (isinf((op - 1)->value.realval)) |
162 | 1 | return_error(gs_error_undefinedresult); |
163 | 6.79M | #endif |
164 | 6.79M | make_real(op - 1, result); |
165 | 6.79M | pop(1); |
166 | 6.79M | return 0; |
167 | 6.79M | } |
168 | | |
169 | | /* <posnum> ln <real> */ |
170 | | int |
171 | | zln(i_ctx_t *i_ctx_p) |
172 | 53 | { |
173 | 53 | os_ptr op = osp; |
174 | 53 | double num; |
175 | 53 | int code = real_param(op, &num); |
176 | | |
177 | 53 | if (code < 0) |
178 | 13 | return code; |
179 | 40 | if (num <= 0.0) |
180 | 3 | return_error(gs_error_rangecheck); |
181 | 37 | make_real(op, log(num)); |
182 | 37 | return 0; |
183 | 40 | } |
184 | | |
185 | | /* <posnum> log <real> */ |
186 | | int |
187 | | zlog(i_ctx_t *i_ctx_p) |
188 | 19 | { |
189 | 19 | os_ptr op = osp; |
190 | 19 | double num; |
191 | 19 | int code = real_param(op, &num); |
192 | | |
193 | 19 | if (code < 0) |
194 | 11 | return code; |
195 | 8 | if (num <= 0.0) |
196 | 2 | return_error(gs_error_rangecheck); |
197 | 6 | make_real(op, log10(num)); |
198 | 6 | return 0; |
199 | 8 | } |
200 | | |
201 | | /* - rand <int> */ |
202 | | static int |
203 | | zrand(i_ctx_t *i_ctx_p) |
204 | 976k | { |
205 | 976k | os_ptr op = osp; |
206 | | |
207 | | /* |
208 | | * We use an algorithm from CACM 31 no. 10, pp. 1192-1201, |
209 | | * October 1988. According to a posting by Ed Taft on |
210 | | * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters |
211 | | * use this algorithm too: |
212 | | * x[n+1] = (16807 * x[n]) mod (2^31 - 1) |
213 | | */ |
214 | 976k | #define A 16807 |
215 | 976k | #define M 0x7fffffff |
216 | 1.95M | #define Q 127773 /* M / A */ |
217 | 976k | #define R 2836 /* M % A */ |
218 | 976k | zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q); |
219 | | /* Note that zrand_state cannot be 0 here. */ |
220 | 976k | if (zrand_state <= 0) |
221 | 12.5k | zrand_state += M; |
222 | 976k | #undef A |
223 | 976k | #undef M |
224 | 976k | #undef Q |
225 | 976k | #undef R |
226 | 976k | push(1); |
227 | 976k | make_int(op, zrand_state); |
228 | 976k | return 0; |
229 | 976k | } |
230 | | |
231 | | /* <int> srand - */ |
232 | | static int |
233 | | zsrand(i_ctx_t *i_ctx_p) |
234 | 38.7k | { |
235 | 38.7k | os_ptr op = osp; |
236 | 38.7k | int state; |
237 | | |
238 | 38.7k | check_type(*op, t_integer); |
239 | 38.7k | state = op->value.intval; |
240 | | /* |
241 | | * The following somewhat bizarre adjustments are according to |
242 | | * public information from Adobe describing their implementation. |
243 | | */ |
244 | 38.7k | if (state < 1) |
245 | 2.73k | state = -(state % 0x7ffffffe) + 1; |
246 | 35.9k | else if (state > 0x7ffffffe) |
247 | 0 | state = 0x7ffffffe; |
248 | 38.7k | zrand_state = state; |
249 | 38.7k | pop(1); |
250 | 38.7k | return 0; |
251 | 38.7k | } |
252 | | |
253 | | /* - rrand <int> */ |
254 | | static int |
255 | | zrrand(i_ctx_t *i_ctx_p) |
256 | 22 | { |
257 | 22 | os_ptr op = osp; |
258 | | |
259 | 22 | push(1); |
260 | 22 | make_int(op, zrand_state); |
261 | 22 | return 0; |
262 | 22 | } |
263 | | |
264 | | /* ------ Initialization procedure ------ */ |
265 | | |
266 | | const op_def zmath_op_defs[] = |
267 | | { |
268 | | {"1arccos", zarccos}, /* extension */ |
269 | | {"1arcsin", zarcsin}, /* extension */ |
270 | | {"2atan", zatan}, |
271 | | {"1cos", zcos}, |
272 | | {"2exp", zexp}, |
273 | | {"1ln", zln}, |
274 | | {"1log", zlog}, |
275 | | {"0rand", zrand}, |
276 | | {"0rrand", zrrand}, |
277 | | {"1sin", zsin}, |
278 | | {"1sqrt", zsqrt}, |
279 | | {"1srand", zsrand}, |
280 | | op_def_end(0) |
281 | | }; |