Commit | Line | Data |
---|---|---|
d330ed3f WJ |
1 | /* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zmath.c */ | |
21 | /* Mathematical operators for GhostScript */ | |
22 | #include "math_.h" | |
23 | #include "ghost.h" | |
24 | #include "errors.h" | |
25 | #include "oper.h" | |
26 | #include "store.h" | |
27 | ||
28 | /* Factors for converting between degrees and radians */ | |
29 | double degrees_to_radians = M_PI / 180.0; | |
30 | double radians_to_degrees = 180.0 / M_PI; | |
31 | ||
32 | /* Current state of random number generator. */ | |
33 | /* We have to implement this ourselves because */ | |
34 | /* the Unix rand doesn't provide anything equivalent to rrand. */ | |
35 | private long rand_state; | |
36 | ||
37 | /* Initialize the random number generator. */ | |
38 | private void | |
39 | zmath_init() | |
40 | { rand_state = 1; | |
41 | } | |
42 | ||
43 | /****** NOTE: none of these operators currently ******/ | |
44 | /****** check for floating over- or underflow. ******/ | |
45 | ||
46 | /* sqrt */ | |
47 | int | |
48 | zsqrt(register os_ptr op) | |
49 | { float num; | |
50 | int code = num_params(op, 1, &num); | |
51 | if ( code < 0 ) return code; | |
52 | if ( num < 0.0 ) return e_rangecheck; | |
53 | make_real(op, sqrt(num)); | |
54 | return 0; | |
55 | } | |
56 | ||
57 | /* arccos */ | |
58 | int | |
59 | zarccos(register os_ptr op) | |
60 | { float num, result; | |
61 | int code = num_params(op, 1, &num); | |
62 | if ( code < 0 ) return code; | |
63 | result = acos(num) * radians_to_degrees; | |
64 | make_real(op, result); | |
65 | return 0; | |
66 | } | |
67 | ||
68 | /* arcsin */ | |
69 | int | |
70 | zarcsin(register os_ptr op) | |
71 | { float num, result; | |
72 | int code = num_params(op, 1, &num); | |
73 | if ( code < 0 ) return code; | |
74 | result = asin(num) * radians_to_degrees; | |
75 | make_real(op, result); | |
76 | return 0; | |
77 | } | |
78 | ||
79 | /* atan */ | |
80 | int | |
81 | zatan(register os_ptr op) | |
82 | { float args[2]; | |
83 | float result; | |
84 | int code = num_params(op, 2, args); | |
85 | if ( code < 0 ) return code; | |
86 | if ( args[0] == 0 ) /* on X-axis, special case */ | |
87 | { if ( args[1] == 0 ) return e_undefinedresult; | |
88 | result = (args[1] < 0 ? 180 : 0); | |
89 | } | |
90 | else | |
91 | { result = atan2(args[0], args[1]) * radians_to_degrees; | |
92 | if ( result < 0 ) result += 360; | |
93 | } | |
94 | make_real(op - 1, result); | |
95 | pop(1); | |
96 | return 0; | |
97 | } | |
98 | ||
99 | /* cos */ | |
100 | int | |
101 | zcos(register os_ptr op) | |
102 | { float angle; | |
103 | int code = num_params(op, 1, &angle); | |
104 | if ( code < 0 ) return code; | |
105 | make_real(op, cos(angle * degrees_to_radians)); | |
106 | return 0; | |
107 | } | |
108 | ||
109 | /* sin */ | |
110 | int | |
111 | zsin(register os_ptr op) | |
112 | { float angle; | |
113 | int code = num_params(op, 1, &angle); | |
114 | if ( code < 0 ) return code; | |
115 | make_real(op, sin(angle * degrees_to_radians)); | |
116 | return 0; | |
117 | } | |
118 | ||
119 | /* exp */ | |
120 | int | |
121 | zexp(register os_ptr op) | |
122 | { float args[2]; | |
123 | float result; | |
124 | double ipart; | |
125 | int code = num_params(op, 2, args); | |
126 | if ( code < 0 ) return code; | |
127 | if ( args[0] == 0.0 && args[1] == 0.0 ) return e_undefinedresult; | |
128 | if ( args[0] < 0.0 && modf(args[1], &ipart) != 0.0 ) | |
129 | return e_undefinedresult; | |
130 | result = pow(args[0], args[1]); | |
131 | make_real(op - 1, result); | |
132 | pop(1); | |
133 | return 0; | |
134 | } | |
135 | ||
136 | /* ln */ | |
137 | int | |
138 | zln(register os_ptr op) | |
139 | { float num; | |
140 | int code = num_params(op, 1, &num); | |
141 | if ( code < 0 ) return code; | |
142 | if ( num <= 0.0 ) return e_rangecheck; | |
143 | make_real(op, log(num)); | |
144 | return 0; | |
145 | } | |
146 | ||
147 | /* log */ | |
148 | int | |
149 | zlog(register os_ptr op) | |
150 | { float num; | |
151 | int code = num_params(op, 1, &num); | |
152 | if ( code < 0 ) return code; | |
153 | if ( num <= 0.0 ) return e_rangecheck; | |
154 | make_real(op, log10(num)); | |
155 | return 0; | |
156 | } | |
157 | ||
158 | /* rand */ | |
159 | int | |
160 | zrand(register os_ptr op) | |
161 | { /* | |
162 | * We use an algorithm from CACM 31 no. 10, pp. 1192-1201, | |
163 | * October 1988. According to a posting by Ed Taft on | |
164 | * comp.lang.postscript, Level 2 (Adobe) PostScript interpreters use | |
165 | * this algorithm too: | |
166 | * x[n+1] = (16807 * x[n]) mod (2^31 - 1) | |
167 | */ | |
168 | #define A 16807 | |
169 | #define M 0x7fffffff | |
170 | #define Q 127773 /* M / A */ | |
171 | #define R 2836 /* M % A */ | |
172 | rand_state = A * (rand_state % Q) - R * (rand_state / Q); | |
173 | while ( rand_state <= 0 ) rand_state += M; | |
174 | #undef A | |
175 | #undef M | |
176 | #undef Q | |
177 | #undef R | |
178 | push(1); | |
179 | make_int(op, rand_state); | |
180 | return 0; | |
181 | } | |
182 | ||
183 | /* srand */ | |
184 | int | |
185 | zsrand(register os_ptr op) | |
186 | { check_type(*op, t_integer); | |
187 | rand_state = op->value.intval; | |
188 | pop(1); | |
189 | return 0; | |
190 | } | |
191 | ||
192 | /* rrand */ | |
193 | int | |
194 | zrrand(register os_ptr op) | |
195 | { push(1); | |
196 | make_int(op, rand_state); | |
197 | return 0; | |
198 | } | |
199 | ||
200 | /* ------ Initialization procedure ------ */ | |
201 | ||
202 | op_def zmath_op_defs[] = { | |
203 | {"1arccos", zarccos}, /* extension */ | |
204 | {"1arcsin", zarcsin}, /* extension */ | |
205 | {"2atan", zatan}, | |
206 | {"1cos", zcos}, | |
207 | {"2exp", zexp}, | |
208 | {"1ln", zln}, | |
209 | {"1log", zlog}, | |
210 | {"0rand", zrand}, | |
211 | {"0rrand", zrrand}, | |
212 | {"1sin", zsin}, | |
213 | {"1sqrt", zsqrt}, | |
214 | {"1srand", zsrand}, | |
215 | op_def_end(zmath_init) | |
216 | }; |