/src/ghostpdl/psi/zarith.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 | | /* Arithmetic operators */ |
18 | | #include "math_.h" |
19 | | #include "ghost.h" |
20 | | #include "oper.h" |
21 | | #include "store.h" |
22 | | #include "gsstate.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 | | static int mul_64_64_overflowcheck(int64_t abc, int64_t def, int64_t *res); |
30 | | |
31 | | /* <num1> <num2> add <sum> */ |
32 | | /* We make this into a separate procedure because */ |
33 | | /* the interpreter will almost always call it directly. */ |
34 | | int |
35 | | zop_add(i_ctx_t *i_ctx_p) |
36 | 584M | { |
37 | 584M | register os_ptr op = osp; |
38 | 584M | float result; |
39 | | |
40 | 584M | check_op(2); |
41 | 584M | switch (r_type(op)) { |
42 | 10 | default: |
43 | 10 | return_op_typecheck(op); |
44 | 61.4M | case t_real: |
45 | 61.4M | switch (r_type(op - 1)) { |
46 | 11 | default: |
47 | 11 | return_op_typecheck(op - 1); |
48 | 33.6M | case t_real: |
49 | 33.6M | result = op[-1].value.realval + op->value.realval; |
50 | 33.6M | #ifdef HAVE_ISINF |
51 | 33.6M | if (isinf(result)) |
52 | 4 | return_error(gs_error_undefinedresult); |
53 | 33.6M | #endif |
54 | 33.6M | #ifdef HAVE_ISNAN |
55 | 33.6M | if (isnan(result)) |
56 | 0 | return_error(gs_error_undefinedresult); |
57 | 33.6M | #endif |
58 | 33.6M | op[-1].value.realval = result; |
59 | 33.6M | break; |
60 | 27.8M | case t_integer: |
61 | 27.8M | make_real(op - 1, (double)op[-1].value.intval + op->value.realval); |
62 | 61.4M | } |
63 | 61.4M | break; |
64 | 523M | case t_integer: |
65 | 523M | switch (r_type(op - 1)) { |
66 | 9 | default: |
67 | 9 | return_op_typecheck(op - 1); |
68 | 56.7M | case t_real: |
69 | 56.7M | result = op[-1].value.realval + (double)op->value.intval; |
70 | 56.7M | #ifdef HAVE_ISINF |
71 | 56.7M | if (isinf(result)) |
72 | 2 | return_error(gs_error_undefinedresult); |
73 | 56.7M | #endif |
74 | 56.7M | #ifdef HAVE_ISNAN |
75 | 56.7M | if (isnan(result)) |
76 | 0 | return_error(gs_error_undefinedresult); |
77 | 56.7M | #endif |
78 | 56.7M | op[-1].value.realval = result; |
79 | 56.7M | break; |
80 | 466M | case t_integer: { |
81 | 466M | if (sizeof(ps_int) != 4 && gs_currentcpsimode(imemory)) { |
82 | 0 | ps_int32 int1 = (ps_int32)op[-1].value.intval; |
83 | 0 | ps_int32 int2 = (ps_int32)op->value.intval; |
84 | |
|
85 | 0 | if (((int1 += int2) ^ int2) < 0 && |
86 | 0 | ((int1 - int2) ^ int2) >= 0 |
87 | 0 | ) { /* Overflow, convert to real */ |
88 | 0 | make_real(op - 1, (double)(int1 - int2) + int2); |
89 | 0 | } |
90 | 0 | else { |
91 | 0 | op[-1].value.intval = (ps_int)int1; |
92 | 0 | } |
93 | 0 | } |
94 | 466M | else { |
95 | 466M | ps_int int2 = op->value.intval; |
96 | | |
97 | 466M | if (((op[-1].value.intval += int2) ^ int2) < 0 && |
98 | 466M | ((op[-1].value.intval - int2) ^ int2) >= 0 |
99 | 466M | ) { /* Overflow, convert to real */ |
100 | 323 | make_real(op - 1, (double)(op[-1].value.intval - int2) + int2); |
101 | 323 | } |
102 | 466M | } |
103 | 466M | } |
104 | 523M | } |
105 | 584M | } |
106 | 584M | return 0; |
107 | 584M | } |
108 | | int |
109 | | zadd(i_ctx_t *i_ctx_p) |
110 | 0 | { |
111 | 0 | int code = zop_add(i_ctx_p); |
112 | |
|
113 | 0 | if (code == 0) { |
114 | 0 | pop(1); |
115 | 0 | } |
116 | 0 | return code; |
117 | 0 | } |
118 | | |
119 | | /* <num1> <num2> div <real_quotient> */ |
120 | | int |
121 | | zdiv(i_ctx_t *i_ctx_p) |
122 | 41.0M | { |
123 | 41.0M | os_ptr op = osp; |
124 | 41.0M | os_ptr op1 = op - 1; |
125 | 41.0M | float result; |
126 | | |
127 | 41.0M | check_op(2); |
128 | | /* We can't use the non_int_cases macro, */ |
129 | | /* because we have to check explicitly for op == 0. */ |
130 | 41.0M | switch (r_type(op)) { |
131 | 13 | default: |
132 | 13 | return_op_typecheck(op); |
133 | 1.79M | case t_real: |
134 | 1.79M | if (op->value.realval == 0) |
135 | 8 | return_error(gs_error_undefinedresult); |
136 | 1.79M | switch (r_type(op1)) { |
137 | 9 | default: |
138 | 9 | return_op_typecheck(op1); |
139 | 1.67M | case t_real: |
140 | 1.67M | result = op1->value.realval / op->value.realval; |
141 | 1.67M | #ifdef HAVE_ISINF |
142 | 1.67M | if (isinf(result)) |
143 | 4 | return_error(gs_error_undefinedresult); |
144 | 1.67M | #endif |
145 | 1.67M | #ifdef HAVE_ISNAN |
146 | 1.67M | if (isnan(result)) |
147 | 1 | return_error(gs_error_undefinedresult); |
148 | 1.67M | #endif |
149 | 1.67M | op1->value.realval = result; |
150 | 1.67M | break; |
151 | 115k | case t_integer: |
152 | 115k | result = (double)op1->value.intval / op->value.realval; |
153 | 115k | #ifdef HAVE_ISINF |
154 | 115k | if (isinf(result)) |
155 | 0 | return_error(gs_error_undefinedresult); |
156 | 115k | #endif |
157 | 115k | #ifdef HAVE_ISNAN |
158 | 115k | if (isnan(result)) |
159 | 0 | return_error(gs_error_undefinedresult); |
160 | 115k | #endif |
161 | 1.79M | make_real(op1, result); |
162 | 1.79M | } |
163 | 1.79M | break; |
164 | 39.2M | case t_integer: |
165 | 39.2M | if (op->value.intval == 0) |
166 | 15 | return_error(gs_error_undefinedresult); |
167 | 39.2M | switch (r_type(op1)) { |
168 | 14 | default: |
169 | 14 | return_op_typecheck(op1); |
170 | 34.2M | case t_real: |
171 | 34.2M | result = op1->value.realval / (double)op->value.intval; |
172 | 34.2M | #ifdef HAVE_ISINF |
173 | 34.2M | if (isinf(result)) |
174 | 0 | return_error(gs_error_undefinedresult); |
175 | 34.2M | #endif |
176 | 34.2M | #ifdef HAVE_ISNAN |
177 | 34.2M | if (isnan(result)) |
178 | 0 | return_error(gs_error_undefinedresult); |
179 | 34.2M | #endif |
180 | 34.2M | op1->value.realval = result; |
181 | 34.2M | break; |
182 | 5.01M | case t_integer: |
183 | 5.01M | result = (double)op1->value.intval / (double)op->value.intval; |
184 | 5.01M | #ifdef HAVE_ISINF |
185 | 5.01M | if (isinf(result)) |
186 | 0 | return_error(gs_error_undefinedresult); |
187 | 5.01M | #endif |
188 | 5.01M | #ifdef HAVE_ISNAN |
189 | 5.01M | if (isnan(result)) |
190 | 0 | return_error(gs_error_undefinedresult); |
191 | 5.01M | #endif |
192 | 39.2M | make_real(op1, result); |
193 | 39.2M | } |
194 | 41.0M | } |
195 | 41.0M | pop(1); |
196 | 41.0M | return 0; |
197 | 41.0M | } |
198 | | |
199 | | /* |
200 | | To detect 64bit x 64bit multiplication overflowing, consider |
201 | | breaking the numbers down into 32bit chunks. |
202 | | |
203 | | abc = (a<<64) + (b<<32) + c |
204 | | (where a is 0 or -1, and b and c are 32bit unsigned. |
205 | | |
206 | | Similarly: |
207 | | |
208 | | def = (d<<64) + (b<<32) + f |
209 | | |
210 | | Then: |
211 | | |
212 | | abc.def = ((a<<64) + (b<<32) + c) * ((d<<64) + (e<<32) + f) |
213 | | = (a<<64).def + (d<<64).abc + (b<<32).(e<<32) + |
214 | | (b<<32).f + (e<<32).c + cf |
215 | | = (a.def + d.abc + b.e)<<64 + (b.f + e.c)<<32 + cf |
216 | | |
217 | | */ |
218 | | |
219 | | static int mul_64_64_overflowcheck(int64_t abc, int64_t def, int64_t *res) |
220 | 11.7M | { |
221 | 11.7M | uint32_t b = (abc>>32); |
222 | 11.7M | uint32_t c = (uint32_t)abc; |
223 | 11.7M | uint32_t e = (def>>32); |
224 | 11.7M | uint32_t f = (uint32_t)def; |
225 | 11.7M | uint64_t low, mid, high, bf, ec; |
226 | | |
227 | | /* Low contribution */ |
228 | 11.7M | low = (uint64_t)c * (uint64_t)f; |
229 | | /* Mid contributions */ |
230 | 11.7M | bf = (uint64_t)b * (uint64_t)f; |
231 | 11.7M | ec = (uint64_t)e * (uint64_t)c; |
232 | | /* Top contribution */ |
233 | 11.7M | high = (uint64_t)b * (uint64_t)e; |
234 | 11.7M | if (abc < 0) |
235 | 366 | high -= def; |
236 | 11.7M | if (def < 0) |
237 | 42 | high -= abc; |
238 | | /* How do we check for carries from 64bit unsigned adds? |
239 | | * x + y >= (1<<64) == x >= (1<<64) - y |
240 | | * == x > (1<<64) - y - 1 |
241 | | * if we consider just 64bits, this is: |
242 | | * x > NOT y |
243 | | */ |
244 | 11.7M | if (bf > ~ec) |
245 | 14 | high += ((uint64_t)1)<<32; |
246 | 11.7M | mid = bf + ec; |
247 | 11.7M | if (low > ~(mid<<32)) |
248 | 14 | high += 1; |
249 | 11.7M | high += (mid>>32); |
250 | 11.7M | low += (mid<<32); |
251 | | |
252 | 11.7M | *res = low; |
253 | | |
254 | 11.7M | return (int64_t)low < 0 ? high != -1 : high != 0; |
255 | 11.7M | } |
256 | | |
257 | | /* <num1> <num2> mul <product> */ |
258 | | int |
259 | | zmul(i_ctx_t *i_ctx_p) |
260 | 130M | { |
261 | 130M | os_ptr op = osp; |
262 | 130M | float result; |
263 | | |
264 | 130M | switch (r_type(op)) { |
265 | 20 | default: |
266 | 20 | return_op_typecheck(op); |
267 | 61.6M | case t_real: |
268 | 61.6M | switch (r_type(op - 1)) { |
269 | 9 | default: |
270 | 9 | return_op_typecheck(op - 1); |
271 | 60.6M | case t_real: |
272 | 60.6M | result = op[-1].value.realval * op->value.realval; |
273 | 60.6M | #ifdef HAVE_ISINF |
274 | 60.6M | if (isinf(result)) |
275 | 33 | return_error(gs_error_undefinedresult); |
276 | 60.6M | #endif |
277 | 60.6M | #ifdef HAVE_ISNAN |
278 | 60.6M | if (isnan(result)) |
279 | 0 | return_error(gs_error_undefinedresult); |
280 | 60.6M | #endif |
281 | 60.6M | op[-1].value.realval = result; |
282 | 60.6M | break; |
283 | 1.01M | case t_integer: |
284 | 1.01M | result = (double)op[-1].value.intval * op->value.realval; |
285 | 1.01M | make_real(op - 1, result); |
286 | 61.6M | } |
287 | 61.6M | break; |
288 | 69.1M | case t_integer: |
289 | 69.1M | switch (r_type(op - 1)) { |
290 | 11 | default: |
291 | 11 | return_op_typecheck(op - 1); |
292 | 57.4M | case t_real: |
293 | 57.4M | result = op[-1].value.realval * (double)op->value.intval; |
294 | 57.4M | #ifdef HAVE_ISINF |
295 | 57.4M | if (isinf(result)) |
296 | 4 | return_error(gs_error_undefinedresult); |
297 | 57.4M | #endif |
298 | 57.4M | #ifdef HAVE_ISNAN |
299 | 57.4M | if (isnan(result)) |
300 | 0 | return_error(gs_error_undefinedresult); |
301 | 57.4M | #endif |
302 | 57.4M | op[-1].value.realval = result; |
303 | 57.4M | break; |
304 | 11.7M | case t_integer: { |
305 | 11.7M | if (sizeof(ps_int) != 4 && gs_currentcpsimode(imemory)) { |
306 | 0 | double ab = (double)op[-1].value.intval * op->value.intval; |
307 | 0 | if (ab > (double)MAX_PS_INT32) /* (double)0x7fffffff */ |
308 | 0 | make_real(op - 1, ab); |
309 | 0 | else if (ab < (double)MIN_PS_INT32) /* (double)(int)0x80000000 */ |
310 | 0 | make_real(op - 1, ab); |
311 | 0 | else |
312 | 0 | op[-1].value.intval = (ps_int)ab; |
313 | 0 | } |
314 | 11.7M | else { |
315 | 11.7M | int64_t result; |
316 | 11.7M | if (mul_64_64_overflowcheck(op[-1].value.intval, op->value.intval, &result)) { |
317 | 2 | double ab = (double)op[-1].value.intval * op->value.intval; |
318 | 2 | make_real(op - 1, ab); |
319 | 11.7M | } else { |
320 | 11.7M | op[-1].value.intval = result; |
321 | 11.7M | } |
322 | 11.7M | } |
323 | 11.7M | } |
324 | 69.1M | } |
325 | 130M | } |
326 | 130M | pop(1); |
327 | 130M | return 0; |
328 | 130M | } |
329 | | |
330 | | /* <num1> <num2> sub <difference> */ |
331 | | /* We make this into a separate procedure because */ |
332 | | /* the interpreter will almost always call it directly. */ |
333 | | int |
334 | | zop_sub(i_ctx_t *i_ctx_p) |
335 | 106M | { |
336 | 106M | register os_ptr op = osp; |
337 | | |
338 | 106M | check_op(2); |
339 | 106M | switch (r_type(op)) { |
340 | 93 | default: |
341 | 93 | return_op_typecheck(op); |
342 | 30.8M | case t_real: |
343 | 30.8M | switch (r_type(op - 1)) { |
344 | 10 | default: |
345 | 10 | return_op_typecheck(op - 1); |
346 | 306k | case t_real: |
347 | 306k | op[-1].value.realval -= op->value.realval; |
348 | 306k | break; |
349 | 30.5M | case t_integer: |
350 | 30.5M | make_real(op - 1, (double)op[-1].value.intval - op->value.realval); |
351 | 30.8M | } |
352 | 30.8M | break; |
353 | 76.0M | case t_integer: |
354 | 76.0M | switch (r_type(op - 1)) { |
355 | 9 | default: |
356 | 9 | return_op_typecheck(op - 1); |
357 | 72.7k | case t_real: |
358 | 72.7k | op[-1].value.realval -= (double)op->value.intval; |
359 | 72.7k | break; |
360 | 75.9M | case t_integer: { |
361 | 75.9M | if (sizeof(ps_int) != 4 && gs_currentcpsimode(imemory)) { |
362 | 0 | ps_int32 int1 = (ps_int)op[-1].value.intval; |
363 | 0 | ps_int32 int2 = (ps_int)op->value.intval; |
364 | 0 | ps_int32 int3; |
365 | |
|
366 | 0 | if ((int1 ^ (int3 = int1 - int2)) < 0 && |
367 | 0 | (int1 ^ int2) < 0 |
368 | 0 | ) { /* Overflow, convert to real */ |
369 | 0 | make_real(op - 1, (float)int1 - op->value.intval); |
370 | 0 | } |
371 | 0 | else { |
372 | 0 | op[-1].value.intval = (ps_int)int3; |
373 | 0 | } |
374 | 0 | } |
375 | 75.9M | else { |
376 | 75.9M | ps_int int1 = op[-1].value.intval; |
377 | | |
378 | 75.9M | if ((int1 ^ (op[-1].value.intval = int1 - op->value.intval)) < 0 && |
379 | 75.9M | (int1 ^ op->value.intval) < 0 |
380 | 75.9M | ) { /* Overflow, convert to real */ |
381 | 0 | make_real(op - 1, (float)int1 - op->value.intval); |
382 | 0 | } |
383 | 75.9M | } |
384 | 75.9M | } |
385 | 76.0M | } |
386 | 106M | } |
387 | 106M | return 0; |
388 | 106M | } |
389 | | int |
390 | | zsub(i_ctx_t *i_ctx_p) |
391 | 0 | { |
392 | 0 | int code = zop_sub(i_ctx_p); |
393 | |
|
394 | 0 | if (code == 0) { |
395 | 0 | pop(1); |
396 | 0 | } |
397 | 0 | return code; |
398 | 0 | } |
399 | | |
400 | | /* <num1> <num2> idiv <int_quotient> */ |
401 | | int |
402 | | zidiv(i_ctx_t *i_ctx_p) |
403 | 43.0M | { |
404 | 43.0M | os_ptr op = osp; |
405 | | |
406 | 43.0M | check_op(2); |
407 | 43.0M | check_type(*op, t_integer); |
408 | 43.0M | check_type(op[-1], t_integer); |
409 | 43.0M | if (sizeof(ps_int) && gs_currentcpsimode(imemory)) { |
410 | 0 | int tmpval; |
411 | 0 | if ((op->value.intval == 0) || (op[-1].value.intval == (ps_int)MIN_PS_INT32 && op->value.intval == -1)) { |
412 | | /* Anomalous boundary case: -MININT / -1, fail. */ |
413 | 0 | return_error(gs_error_undefinedresult); |
414 | 0 | } |
415 | 0 | tmpval = (int)op[-1].value.intval / op->value.intval; |
416 | 0 | op[-1].value.intval = (int64_t)tmpval; |
417 | 0 | } |
418 | 43.0M | else { |
419 | 43.0M | if ((op->value.intval == 0) || (op[-1].value.intval == MIN_PS_INT && op->value.intval == -1)) { |
420 | | /* Anomalous boundary case: -MININT / -1, fail. */ |
421 | 6 | return_error(gs_error_undefinedresult); |
422 | 6 | } |
423 | 43.0M | op[-1].value.intval /= op->value.intval; |
424 | 43.0M | } |
425 | 43.0M | pop(1); |
426 | 43.0M | return 0; |
427 | 43.0M | } |
428 | | |
429 | | /* <int1> <int2> mod <remainder> */ |
430 | | int |
431 | | zmod(i_ctx_t *i_ctx_p) |
432 | 31.3M | { |
433 | 31.3M | os_ptr op = osp; |
434 | | |
435 | 31.3M | check_op(2); |
436 | 31.3M | check_type(*op, t_integer); |
437 | 31.3M | check_type(op[-1], t_integer); |
438 | 31.3M | if (op->value.intval == 0 || op[-1].value.intval == MIN_PS_INT) |
439 | 7 | return_error(gs_error_undefinedresult); |
440 | 31.3M | op[-1].value.intval %= op->value.intval; |
441 | 31.3M | pop(1); |
442 | 31.3M | return 0; |
443 | 31.3M | } |
444 | | |
445 | | /* <num1> neg <num2> */ |
446 | | int |
447 | | zneg(i_ctx_t *i_ctx_p) |
448 | 6.23M | { |
449 | 6.23M | os_ptr op = osp; |
450 | | |
451 | 6.23M | check_op(1); |
452 | 6.23M | switch (r_type(op)) { |
453 | 10 | default: |
454 | 10 | return_op_typecheck(op); |
455 | 2.16M | case t_real: |
456 | 2.16M | op->value.realval = -op->value.realval; |
457 | 2.16M | break; |
458 | 4.07M | case t_integer: |
459 | 4.07M | if (sizeof(ps_int) != 32 && gs_currentcpsimode(imemory)) { |
460 | 0 | if (((unsigned int)op->value.intval) == MIN_PS_INT32) |
461 | 0 | make_real(op, -(float)(ps_uint32)MIN_PS_INT32); |
462 | 0 | else |
463 | 0 | op->value.intval = -op->value.intval; |
464 | 0 | } |
465 | 4.07M | else { |
466 | 4.07M | if (op->value.intval == MIN_PS_INT) |
467 | 4.07M | make_real(op, -(float)MIN_PS_INT); |
468 | 4.07M | else |
469 | 4.07M | op->value.intval = -op->value.intval; |
470 | 4.07M | } |
471 | 6.23M | } |
472 | 6.23M | return 0; |
473 | 6.23M | } |
474 | | |
475 | | /* <num1> abs <num2> */ |
476 | | int |
477 | | zabs(i_ctx_t *i_ctx_p) |
478 | 33.9M | { |
479 | 33.9M | os_ptr op = osp; |
480 | | |
481 | 33.9M | check_op(1); |
482 | 33.9M | switch (r_type(op)) { |
483 | 86 | default: |
484 | 86 | return_op_typecheck(op); |
485 | 3.25M | case t_real: |
486 | 3.25M | if (op->value.realval >= 0) |
487 | 1.75M | return 0; |
488 | 1.50M | break; |
489 | 30.6M | case t_integer: |
490 | 30.6M | if (op->value.intval >= 0) |
491 | 30.6M | return 0; |
492 | 120 | break; |
493 | 33.9M | } |
494 | 1.50M | return zneg(i_ctx_p); |
495 | 33.9M | } |
496 | | |
497 | | /* <num1> ceiling <num2> */ |
498 | | int |
499 | | zceiling(i_ctx_t *i_ctx_p) |
500 | 239 | { |
501 | 239 | os_ptr op = osp; |
502 | | |
503 | 239 | check_op(1); |
504 | 224 | switch (r_type(op)) { |
505 | 9 | default: |
506 | 9 | return_op_typecheck(op); |
507 | 109 | case t_real: |
508 | 109 | op->value.realval = ceil(op->value.realval); |
509 | 215 | case t_integer:; |
510 | 224 | } |
511 | 215 | return 0; |
512 | 224 | } |
513 | | |
514 | | /* <num1> floor <num2> */ |
515 | | int |
516 | | zfloor(i_ctx_t *i_ctx_p) |
517 | 258 | { |
518 | 258 | os_ptr op = osp; |
519 | | |
520 | 258 | check_op(1); |
521 | 243 | switch (r_type(op)) { |
522 | 7 | default: |
523 | 7 | return_op_typecheck(op); |
524 | 104 | case t_real: |
525 | 104 | op->value.realval = floor(op->value.realval); |
526 | 236 | case t_integer:; |
527 | 243 | } |
528 | 236 | return 0; |
529 | 243 | } |
530 | | |
531 | | /* <num1> round <num2> */ |
532 | | int |
533 | | zround(i_ctx_t *i_ctx_p) |
534 | 4.48k | { |
535 | 4.48k | os_ptr op = osp; |
536 | | |
537 | 4.48k | check_op(1); |
538 | 4.47k | switch (r_type(op)) { |
539 | 10 | default: |
540 | 10 | return_op_typecheck(op); |
541 | 703 | case t_real: |
542 | 703 | op->value.realval = floor(op->value.realval + 0.5); |
543 | 4.46k | case t_integer:; |
544 | 4.47k | } |
545 | 4.46k | return 0; |
546 | 4.47k | } |
547 | | |
548 | | /* <num1> truncate <num2> */ |
549 | | int |
550 | | ztruncate(i_ctx_t *i_ctx_p) |
551 | 3.35M | { |
552 | 3.35M | os_ptr op = osp; |
553 | | |
554 | 3.35M | check_op(1); |
555 | 3.35M | switch (r_type(op)) { |
556 | 10 | default: |
557 | 10 | return_op_typecheck(op); |
558 | 1.53k | case t_real: |
559 | 1.53k | op->value.realval = |
560 | 1.53k | (op->value.realval < 0.0 ? |
561 | 20 | ceil(op->value.realval) : |
562 | 1.53k | floor(op->value.realval)); |
563 | 3.35M | case t_integer:; |
564 | 3.35M | } |
565 | 3.35M | return 0; |
566 | 3.35M | } |
567 | | |
568 | | /* Non-standard operators */ |
569 | | |
570 | | /* <int1> <int2> .bitadd <sum> */ |
571 | | static int |
572 | | zbitadd(i_ctx_t *i_ctx_p) |
573 | 0 | { |
574 | 0 | os_ptr op = osp; |
575 | |
|
576 | 0 | check_op(2); |
577 | 0 | check_type(*op, t_integer); |
578 | 0 | check_type(op[-1], t_integer); |
579 | 0 | op[-1].value.intval += op->value.intval; |
580 | 0 | pop(1); |
581 | 0 | return 0; |
582 | 0 | } |
583 | | |
584 | | /* ------ Initialization table ------ */ |
585 | | |
586 | | const op_def zarith_op_defs[] = |
587 | | { |
588 | | {"1abs", zabs}, |
589 | | {"2add", zadd}, |
590 | | {"2.bitadd", zbitadd}, |
591 | | {"1ceiling", zceiling}, |
592 | | {"2div", zdiv}, |
593 | | {"2idiv", zidiv}, |
594 | | {"1floor", zfloor}, |
595 | | {"2mod", zmod}, |
596 | | {"2mul", zmul}, |
597 | | {"1neg", zneg}, |
598 | | {"1round", zround}, |
599 | | {"2sub", zsub}, |
600 | | {"1truncate", ztruncate}, |
601 | | op_def_end(0) |
602 | | }; |