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