/src/ghostpdl/psi/zmath.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2023 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., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, 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 | 125M | #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 | 1.09M | { |
51 | 1.09M | os_ptr op = osp; |
52 | 1.09M | double num; |
53 | 1.09M | int code; |
54 | | |
55 | 1.09M | check_op(1); |
56 | 1.09M | code = real_param(op, &num); |
57 | | |
58 | 1.09M | if (code < 0) |
59 | 6 | return code; |
60 | 1.09M | if (num < 0.0) |
61 | 5 | return_error(gs_error_rangecheck); |
62 | 1.09M | make_real(op, sqrt(num)); |
63 | 1.09M | return 0; |
64 | 1.09M | } |
65 | | |
66 | | /* <num> arccos <real> */ |
67 | | static int |
68 | | zarccos(i_ctx_t *i_ctx_p) |
69 | 0 | { |
70 | 0 | os_ptr op = osp; |
71 | 0 | double num, result; |
72 | 0 | int code; |
73 | |
|
74 | 0 | check_op(1); |
75 | 0 | code = real_param(op, &num); |
76 | |
|
77 | 0 | if (code < 0) |
78 | 0 | return code; |
79 | 0 | if (num < -1 || num > 1) |
80 | 0 | return_error(gs_error_rangecheck); |
81 | | |
82 | 0 | result = acos(num) * radians_to_degrees; |
83 | 0 | make_real(op, result); |
84 | 0 | return 0; |
85 | 0 | } |
86 | | |
87 | | /* <num> arcsin <real> */ |
88 | | static int |
89 | | zarcsin(i_ctx_t *i_ctx_p) |
90 | 0 | { |
91 | 0 | os_ptr op = osp; |
92 | 0 | double num, result; |
93 | 0 | int code; |
94 | |
|
95 | 0 | check_op(1); |
96 | 0 | code = real_param(op, &num); |
97 | |
|
98 | 0 | if (code < 0) |
99 | 0 | return code; |
100 | 0 | if (num < -1 || num > 1) |
101 | 0 | return_error(gs_error_rangecheck); |
102 | | |
103 | 0 | result = asin(num) * radians_to_degrees; |
104 | 0 | make_real(op, result); |
105 | 0 | return 0; |
106 | 0 | } |
107 | | |
108 | | /* <num> <denom> atan <real> */ |
109 | | int |
110 | | zatan(i_ctx_t *i_ctx_p) |
111 | 879 | { |
112 | 879 | os_ptr op = osp; |
113 | 879 | double args[2]; |
114 | 879 | double result; |
115 | 879 | int code; |
116 | | |
117 | 879 | check_op(2); |
118 | 871 | code = num_params(op, 2, args); |
119 | | |
120 | 871 | if (code < 0) |
121 | 12 | return code; |
122 | 859 | code = gs_atan2_degrees(args[0], args[1], &result); |
123 | 859 | if (code < 0) |
124 | 2 | return code; |
125 | 857 | make_real(op - 1, result); |
126 | 857 | pop(1); |
127 | 857 | return 0; |
128 | 859 | } |
129 | | |
130 | | /* <num> cos <real> */ |
131 | | int |
132 | | zcos(i_ctx_t *i_ctx_p) |
133 | 56.2M | { |
134 | 56.2M | os_ptr op = osp; |
135 | 56.2M | double angle; |
136 | 56.2M | int code; |
137 | | |
138 | 56.2M | check_op(1); |
139 | 56.2M | code = real_param(op, &angle); |
140 | | |
141 | 56.2M | if (code < 0) |
142 | 8 | return code; |
143 | 56.2M | make_real(op, gs_cos_degrees(angle)); |
144 | 56.2M | return 0; |
145 | 56.2M | } |
146 | | |
147 | | /* <num> sin <real> */ |
148 | | int |
149 | | zsin(i_ctx_t *i_ctx_p) |
150 | 217k | { |
151 | 217k | os_ptr op = osp; |
152 | 217k | double angle; |
153 | 217k | int code; |
154 | 217k | check_op(1); |
155 | 217k | code = real_param(op, &angle); |
156 | | |
157 | 217k | if (code < 0) |
158 | 14 | return code; |
159 | 217k | make_real(op, gs_sin_degrees(angle)); |
160 | 217k | return 0; |
161 | 217k | } |
162 | | |
163 | | /* <base> <exponent> exp <real> */ |
164 | | int |
165 | | zexp(i_ctx_t *i_ctx_p) |
166 | 15.0M | { |
167 | 15.0M | os_ptr op = osp; |
168 | 15.0M | double args[2]; |
169 | 15.0M | double result; |
170 | 15.0M | double ipart; |
171 | 15.0M | int code; |
172 | | |
173 | 15.0M | check_op(2); |
174 | 15.0M | code = num_params(op, 2, args); |
175 | | |
176 | 15.0M | if (code < 0) |
177 | 5 | return code; |
178 | 15.0M | if (args[0] == 0.0 && args[1] < 0) |
179 | 0 | return_error(gs_error_undefinedresult); |
180 | 15.0M | if (args[0] < 0.0 && modf(args[1], &ipart) != 0.0) |
181 | 0 | return_error(gs_error_undefinedresult); |
182 | 15.0M | if (args[0] == 0.0 && args[1] == 0.0) |
183 | 9 | result = 1.0; /* match Adobe; can't rely on C library */ |
184 | 15.0M | else |
185 | 15.0M | result = pow(args[0], args[1]); |
186 | 15.0M | #ifdef HAVE_ISINF |
187 | 15.0M | if (isinf(result)) |
188 | 4 | return_error(gs_error_undefinedresult); |
189 | 15.0M | #endif |
190 | 15.0M | make_real(op - 1, result); |
191 | 15.0M | pop(1); |
192 | 15.0M | return 0; |
193 | 15.0M | } |
194 | | |
195 | | /* <posnum> ln <real> */ |
196 | | int |
197 | | zln(i_ctx_t *i_ctx_p) |
198 | 109 | { |
199 | 109 | os_ptr op = osp; |
200 | 109 | double num; |
201 | 109 | int code; |
202 | | |
203 | 109 | check_op(1); |
204 | 94 | code = real_param(op, &num); |
205 | | |
206 | 94 | if (code < 0) |
207 | 8 | return code; |
208 | 86 | if (num <= 0.0) |
209 | 5 | return_error(gs_error_rangecheck); |
210 | 81 | make_real(op, log(num)); |
211 | 81 | return 0; |
212 | 86 | } |
213 | | |
214 | | /* <posnum> log <real> */ |
215 | | int |
216 | | zlog(i_ctx_t *i_ctx_p) |
217 | 37 | { |
218 | 37 | os_ptr op = osp; |
219 | 37 | double num; |
220 | 37 | int code; |
221 | | |
222 | 37 | check_op(1); |
223 | 23 | code = real_param(op, &num); |
224 | | |
225 | 23 | if (code < 0) |
226 | 8 | return code; |
227 | 15 | if (num <= 0.0) |
228 | 2 | return_error(gs_error_rangecheck); |
229 | 13 | make_real(op, log10(num)); |
230 | 13 | return 0; |
231 | 15 | } |
232 | | |
233 | | /* - rand <int> */ |
234 | | static int |
235 | | zrand(i_ctx_t *i_ctx_p) |
236 | 31.1M | { |
237 | 31.1M | os_ptr op = osp; |
238 | | |
239 | | /* |
240 | | * We use an algorithm from CACM 31 no. 10, pp. 1192-1201, |
241 | | * October 1988. According to a posting by Ed Taft on |
242 | | * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters |
243 | | * use this algorithm too: |
244 | | * x[n+1] = (16807 * x[n]) mod (2^31 - 1) |
245 | | */ |
246 | 31.1M | #define A 16807 |
247 | 31.1M | #define M 0x7fffffff |
248 | 62.3M | #define Q 127773 /* M / A */ |
249 | 31.1M | #define R 2836 /* M % A */ |
250 | 31.1M | zrand_state = A * (zrand_state % Q) - R * (zrand_state / Q); |
251 | | /* Note that zrand_state cannot be 0 here. */ |
252 | 31.1M | if (zrand_state <= 0) |
253 | 350k | zrand_state += M; |
254 | 31.1M | #undef A |
255 | 31.1M | #undef M |
256 | 31.1M | #undef Q |
257 | 31.1M | #undef R |
258 | 31.1M | push(1); |
259 | 31.1M | make_int(op, zrand_state); |
260 | 31.1M | return 0; |
261 | 31.1M | } |
262 | | |
263 | | /* <int> srand - */ |
264 | | static int |
265 | | zsrand(i_ctx_t *i_ctx_p) |
266 | 704k | { |
267 | 704k | os_ptr op = osp; |
268 | 704k | int state; |
269 | | |
270 | 704k | check_op(1); |
271 | 704k | check_type(*op, t_integer); |
272 | 704k | state = op->value.intval; |
273 | | /* |
274 | | * The following somewhat bizarre adjustments are according to |
275 | | * public information from Adobe describing their implementation. |
276 | | */ |
277 | 704k | if (state < 1) |
278 | 520k | state = -(state % 0x7ffffffe) + 1; |
279 | 183k | else if (state > 0x7ffffffe) |
280 | 0 | state = 0x7ffffffe; |
281 | 704k | zrand_state = state; |
282 | 704k | pop(1); |
283 | 704k | return 0; |
284 | 704k | } |
285 | | |
286 | | /* - rrand <int> */ |
287 | | static int |
288 | | zrrand(i_ctx_t *i_ctx_p) |
289 | 24 | { |
290 | 24 | os_ptr op = osp; |
291 | | |
292 | 24 | push(1); |
293 | 24 | make_int(op, zrand_state); |
294 | 24 | return 0; |
295 | 24 | } |
296 | | |
297 | | /* ------ Initialization procedure ------ */ |
298 | | |
299 | | const op_def zmath_op_defs[] = |
300 | | { |
301 | | {"1arccos", zarccos}, /* extension */ |
302 | | {"1arcsin", zarcsin}, /* extension */ |
303 | | {"2atan", zatan}, |
304 | | {"1cos", zcos}, |
305 | | {"2exp", zexp}, |
306 | | {"1ln", zln}, |
307 | | {"1log", zlog}, |
308 | | {"0rand", zrand}, |
309 | | {"0rrand", zrrand}, |
310 | | {"1sin", zsin}, |
311 | | {"1sqrt", zsqrt}, |
312 | | {"1srand", zsrand}, |
313 | | op_def_end(0) |
314 | | }; |