/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 | 28.8M | { |
37 | 28.8M | register os_ptr op = osp; |
38 | 28.8M | float result; |
39 | | |
40 | 28.8M | check_op(2); |
41 | 28.8M | switch (r_type(op)) { |
42 | 0 | default: |
43 | 0 | return_op_typecheck(op); |
44 | 665k | case t_real: |
45 | 665k | switch (r_type(op - 1)) { |
46 | 1 | default: |
47 | 1 | return_op_typecheck(op - 1); |
48 | 489k | case t_real: |
49 | 489k | result = op[-1].value.realval + op->value.realval; |
50 | 489k | #ifdef HAVE_ISINF |
51 | 489k | if (isinf(result)) |
52 | 0 | return_error(gs_error_undefinedresult); |
53 | 489k | #endif |
54 | 489k | #ifdef HAVE_ISNAN |
55 | 489k | if (isnan(result)) |
56 | 0 | return_error(gs_error_undefinedresult); |
57 | 489k | #endif |
58 | 489k | op[-1].value.realval = result; |
59 | 489k | break; |
60 | 176k | case t_integer: |
61 | 176k | make_real(op - 1, (double)op[-1].value.intval + op->value.realval); |
62 | 665k | } |
63 | 665k | break; |
64 | 28.2M | case t_integer: |
65 | 28.2M | switch (r_type(op - 1)) { |
66 | 0 | default: |
67 | 0 | return_op_typecheck(op - 1); |
68 | 454k | case t_real: |
69 | 454k | result = op[-1].value.realval + (double)op->value.intval; |
70 | 454k | #ifdef HAVE_ISINF |
71 | 454k | if (isinf(result)) |
72 | 0 | return_error(gs_error_undefinedresult); |
73 | 454k | #endif |
74 | 454k | #ifdef HAVE_ISNAN |
75 | 454k | if (isnan(result)) |
76 | 0 | return_error(gs_error_undefinedresult); |
77 | 454k | #endif |
78 | 454k | op[-1].value.realval = result; |
79 | 454k | break; |
80 | 27.7M | case t_integer: { |
81 | 27.7M | 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 | 27.7M | else { |
95 | 27.7M | ps_int int2 = op->value.intval; |
96 | | |
97 | 27.7M | if (((op[-1].value.intval += int2) ^ int2) < 0 && |
98 | 27.7M | ((op[-1].value.intval - int2) ^ int2) >= 0 |
99 | 27.7M | ) { /* Overflow, convert to real */ |
100 | 0 | make_real(op - 1, (double)(op[-1].value.intval - int2) + int2); |
101 | 0 | } |
102 | 27.7M | } |
103 | 27.7M | } |
104 | 28.2M | } |
105 | 28.8M | } |
106 | 28.8M | return 0; |
107 | 28.8M | } |
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 | 435k | { |
123 | 435k | os_ptr op = osp; |
124 | 435k | os_ptr op1 = op - 1; |
125 | 435k | float result; |
126 | | |
127 | 435k | check_op(2); |
128 | | /* We can't use the non_int_cases macro, */ |
129 | | /* because we have to check explicitly for op == 0. */ |
130 | 435k | switch (r_type(op)) { |
131 | 0 | default: |
132 | 0 | return_op_typecheck(op); |
133 | 109k | case t_real: |
134 | 109k | if (op->value.realval == 0) |
135 | 1 | return_error(gs_error_undefinedresult); |
136 | 109k | switch (r_type(op1)) { |
137 | 0 | default: |
138 | 0 | return_op_typecheck(op1); |
139 | 109k | case t_real: |
140 | 109k | result = op1->value.realval / op->value.realval; |
141 | 109k | #ifdef HAVE_ISINF |
142 | 109k | if (isinf(result)) |
143 | 1 | return_error(gs_error_undefinedresult); |
144 | 109k | #endif |
145 | 109k | #ifdef HAVE_ISNAN |
146 | 109k | if (isnan(result)) |
147 | 1 | return_error(gs_error_undefinedresult); |
148 | 109k | #endif |
149 | 109k | op1->value.realval = result; |
150 | 109k | break; |
151 | 63 | case t_integer: |
152 | 63 | result = (double)op1->value.intval / op->value.realval; |
153 | 63 | #ifdef HAVE_ISINF |
154 | 63 | if (isinf(result)) |
155 | 0 | return_error(gs_error_undefinedresult); |
156 | 63 | #endif |
157 | 63 | #ifdef HAVE_ISNAN |
158 | 63 | if (isnan(result)) |
159 | 0 | return_error(gs_error_undefinedresult); |
160 | 63 | #endif |
161 | 109k | make_real(op1, result); |
162 | 109k | } |
163 | 109k | break; |
164 | 325k | case t_integer: |
165 | 325k | if (op->value.intval == 0) |
166 | 0 | return_error(gs_error_undefinedresult); |
167 | 325k | switch (r_type(op1)) { |
168 | 1 | default: |
169 | 1 | return_op_typecheck(op1); |
170 | 306k | case t_real: |
171 | 306k | result = op1->value.realval / (double)op->value.intval; |
172 | 306k | #ifdef HAVE_ISINF |
173 | 306k | if (isinf(result)) |
174 | 0 | return_error(gs_error_undefinedresult); |
175 | 306k | #endif |
176 | 306k | #ifdef HAVE_ISNAN |
177 | 306k | if (isnan(result)) |
178 | 0 | return_error(gs_error_undefinedresult); |
179 | 306k | #endif |
180 | 306k | op1->value.realval = result; |
181 | 306k | break; |
182 | 19.2k | case t_integer: |
183 | 19.2k | result = (double)op1->value.intval / (double)op->value.intval; |
184 | 19.2k | #ifdef HAVE_ISINF |
185 | 19.2k | if (isinf(result)) |
186 | 0 | return_error(gs_error_undefinedresult); |
187 | 19.2k | #endif |
188 | 19.2k | #ifdef HAVE_ISNAN |
189 | 19.2k | if (isnan(result)) |
190 | 0 | return_error(gs_error_undefinedresult); |
191 | 19.2k | #endif |
192 | 325k | make_real(op1, result); |
193 | 325k | } |
194 | 435k | } |
195 | 435k | pop(1); |
196 | 435k | return 0; |
197 | 435k | } |
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 | 704k | { |
221 | 704k | uint32_t b = (abc>>32); |
222 | 704k | uint32_t c = (uint32_t)abc; |
223 | 704k | uint32_t e = (def>>32); |
224 | 704k | uint32_t f = (uint32_t)def; |
225 | 704k | uint64_t low, mid, high, bf, ec; |
226 | | |
227 | | /* Low contribution */ |
228 | 704k | low = (uint64_t)c * (uint64_t)f; |
229 | | /* Mid contributions */ |
230 | 704k | bf = (uint64_t)b * (uint64_t)f; |
231 | 704k | ec = (uint64_t)e * (uint64_t)c; |
232 | | /* Top contribution */ |
233 | 704k | high = (uint64_t)b * (uint64_t)e; |
234 | 704k | if (abc < 0) |
235 | 3 | high -= def; |
236 | 704k | if (def < 0) |
237 | 3 | 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 | 704k | if (bf > ~ec) |
245 | 1 | high += ((uint64_t)1)<<32; |
246 | 704k | mid = bf + ec; |
247 | 704k | if (low > ~(mid<<32)) |
248 | 1 | high += 1; |
249 | 704k | high += (mid>>32); |
250 | 704k | low += (mid<<32); |
251 | | |
252 | 704k | *res = low; |
253 | | |
254 | 704k | return (int64_t)low < 0 ? high != -1 : high != 0; |
255 | 704k | } |
256 | | |
257 | | /* <num1> <num2> mul <product> */ |
258 | | int |
259 | | zmul(i_ctx_t *i_ctx_p) |
260 | 2.04M | { |
261 | 2.04M | os_ptr op = osp; |
262 | 2.04M | float result; |
263 | | |
264 | 2.04M | switch (r_type(op)) { |
265 | 1 | default: |
266 | 1 | return_op_typecheck(op); |
267 | 926k | case t_real: |
268 | 926k | switch (r_type(op - 1)) { |
269 | 1 | default: |
270 | 1 | return_op_typecheck(op - 1); |
271 | 855k | case t_real: |
272 | 855k | result = op[-1].value.realval * op->value.realval; |
273 | 855k | #ifdef HAVE_ISINF |
274 | 855k | if (isinf(result)) |
275 | 0 | return_error(gs_error_undefinedresult); |
276 | 855k | #endif |
277 | 855k | #ifdef HAVE_ISNAN |
278 | 855k | if (isnan(result)) |
279 | 0 | return_error(gs_error_undefinedresult); |
280 | 855k | #endif |
281 | 855k | op[-1].value.realval = result; |
282 | 855k | break; |
283 | 71.6k | case t_integer: |
284 | 71.6k | result = (double)op[-1].value.intval * op->value.realval; |
285 | 71.6k | make_real(op - 1, result); |
286 | 926k | } |
287 | 926k | break; |
288 | 1.12M | case t_integer: |
289 | 1.12M | switch (r_type(op - 1)) { |
290 | 1 | default: |
291 | 1 | return_op_typecheck(op - 1); |
292 | 418k | case t_real: |
293 | 418k | result = op[-1].value.realval * (double)op->value.intval; |
294 | 418k | #ifdef HAVE_ISINF |
295 | 418k | if (isinf(result)) |
296 | 0 | return_error(gs_error_undefinedresult); |
297 | 418k | #endif |
298 | 418k | #ifdef HAVE_ISNAN |
299 | 418k | if (isnan(result)) |
300 | 0 | return_error(gs_error_undefinedresult); |
301 | 418k | #endif |
302 | 418k | op[-1].value.realval = result; |
303 | 418k | break; |
304 | 704k | case t_integer: { |
305 | 704k | 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 | 704k | else { |
315 | 704k | int64_t result; |
316 | 704k | if (mul_64_64_overflowcheck(op[-1].value.intval, op->value.intval, &result)) { |
317 | 0 | double ab = (double)op[-1].value.intval * op->value.intval; |
318 | 0 | make_real(op - 1, ab); |
319 | 704k | } else { |
320 | 704k | op[-1].value.intval = result; |
321 | 704k | } |
322 | 704k | } |
323 | 704k | } |
324 | 1.12M | } |
325 | 2.04M | } |
326 | 2.04M | pop(1); |
327 | 2.04M | return 0; |
328 | 2.04M | } |
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 | 4.49M | { |
336 | 4.49M | register os_ptr op = osp; |
337 | | |
338 | 4.49M | check_op(2); |
339 | 4.49M | switch (r_type(op)) { |
340 | 2 | default: |
341 | 2 | return_op_typecheck(op); |
342 | 184k | case t_real: |
343 | 184k | switch (r_type(op - 1)) { |
344 | 1 | default: |
345 | 1 | return_op_typecheck(op - 1); |
346 | 8.59k | case t_real: |
347 | 8.59k | op[-1].value.realval -= op->value.realval; |
348 | 8.59k | break; |
349 | 176k | case t_integer: |
350 | 176k | make_real(op - 1, (double)op[-1].value.intval - op->value.realval); |
351 | 184k | } |
352 | 184k | break; |
353 | 4.31M | case t_integer: |
354 | 4.31M | switch (r_type(op - 1)) { |
355 | 0 | default: |
356 | 0 | return_op_typecheck(op - 1); |
357 | 4.21k | case t_real: |
358 | 4.21k | op[-1].value.realval -= (double)op->value.intval; |
359 | 4.21k | break; |
360 | 4.31M | case t_integer: { |
361 | 4.31M | 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 | 4.31M | else { |
376 | 4.31M | ps_int int1 = op[-1].value.intval; |
377 | | |
378 | 4.31M | if ((int1 ^ (op[-1].value.intval = int1 - op->value.intval)) < 0 && |
379 | 4.31M | (int1 ^ op->value.intval) < 0 |
380 | 4.31M | ) { /* Overflow, convert to real */ |
381 | 0 | make_real(op - 1, (float)int1 - op->value.intval); |
382 | 0 | } |
383 | 4.31M | } |
384 | 4.31M | } |
385 | 4.31M | } |
386 | 4.49M | } |
387 | 4.49M | return 0; |
388 | 4.49M | } |
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 | 2.53M | { |
404 | 2.53M | os_ptr op = osp; |
405 | | |
406 | 2.53M | check_op(2); |
407 | 2.53M | check_type(*op, t_integer); |
408 | 2.53M | check_type(op[-1], t_integer); |
409 | 2.53M | 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 | 2.53M | else { |
419 | 2.53M | if ((op->value.intval == 0) || (op[-1].value.intval == MIN_PS_INT && op->value.intval == -1)) { |
420 | | /* Anomalous boundary case: -MININT / -1, fail. */ |
421 | 0 | return_error(gs_error_undefinedresult); |
422 | 0 | } |
423 | 2.53M | op[-1].value.intval /= op->value.intval; |
424 | 2.53M | } |
425 | 2.53M | pop(1); |
426 | 2.53M | return 0; |
427 | 2.53M | } |
428 | | |
429 | | /* <int1> <int2> mod <remainder> */ |
430 | | int |
431 | | zmod(i_ctx_t *i_ctx_p) |
432 | 25.3k | { |
433 | 25.3k | os_ptr op = osp; |
434 | | |
435 | 25.3k | check_op(2); |
436 | 25.3k | check_type(*op, t_integer); |
437 | 25.3k | check_type(op[-1], t_integer); |
438 | 25.3k | if (op->value.intval == 0 || op[-1].value.intval == MIN_PS_INT) |
439 | 0 | return_error(gs_error_undefinedresult); |
440 | 25.3k | op[-1].value.intval %= op->value.intval; |
441 | 25.3k | pop(1); |
442 | 25.3k | return 0; |
443 | 25.3k | } |
444 | | |
445 | | /* <num1> neg <num2> */ |
446 | | int |
447 | | zneg(i_ctx_t *i_ctx_p) |
448 | 27.1k | { |
449 | 27.1k | os_ptr op = osp; |
450 | | |
451 | 27.1k | check_op(1); |
452 | 27.1k | switch (r_type(op)) { |
453 | 0 | default: |
454 | 0 | return_op_typecheck(op); |
455 | 8.48k | case t_real: |
456 | 8.48k | op->value.realval = -op->value.realval; |
457 | 8.48k | break; |
458 | 18.6k | case t_integer: |
459 | 18.6k | 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 | 18.6k | else { |
466 | 18.6k | if (op->value.intval == MIN_PS_INT) |
467 | 18.6k | make_real(op, -(float)MIN_PS_INT); |
468 | 18.6k | else |
469 | 18.6k | op->value.intval = -op->value.intval; |
470 | 18.6k | } |
471 | 27.1k | } |
472 | 27.1k | return 0; |
473 | 27.1k | } |
474 | | |
475 | | /* <num1> abs <num2> */ |
476 | | int |
477 | | zabs(i_ctx_t *i_ctx_p) |
478 | 67.8k | { |
479 | 67.8k | os_ptr op = osp; |
480 | | |
481 | 67.8k | check_op(1); |
482 | 67.8k | switch (r_type(op)) { |
483 | 3 | default: |
484 | 3 | return_op_typecheck(op); |
485 | 45.4k | case t_real: |
486 | 45.4k | if (op->value.realval >= 0) |
487 | 42.6k | return 0; |
488 | 2.88k | break; |
489 | 22.4k | case t_integer: |
490 | 22.4k | if (op->value.intval >= 0) |
491 | 22.4k | return 0; |
492 | 2 | break; |
493 | 67.8k | } |
494 | 2.88k | return zneg(i_ctx_p); |
495 | 67.8k | } |
496 | | |
497 | | /* <num1> ceiling <num2> */ |
498 | | int |
499 | | zceiling(i_ctx_t *i_ctx_p) |
500 | 8 | { |
501 | 8 | os_ptr op = osp; |
502 | | |
503 | 8 | check_op(1); |
504 | 8 | switch (r_type(op)) { |
505 | 1 | default: |
506 | 1 | return_op_typecheck(op); |
507 | 3 | case t_real: |
508 | 3 | op->value.realval = ceil(op->value.realval); |
509 | 7 | case t_integer:; |
510 | 8 | } |
511 | 7 | return 0; |
512 | 8 | } |
513 | | |
514 | | /* <num1> floor <num2> */ |
515 | | int |
516 | | zfloor(i_ctx_t *i_ctx_p) |
517 | 8 | { |
518 | 8 | os_ptr op = osp; |
519 | | |
520 | 8 | check_op(1); |
521 | 7 | switch (r_type(op)) { |
522 | 0 | default: |
523 | 0 | return_op_typecheck(op); |
524 | 0 | case t_real: |
525 | 0 | op->value.realval = floor(op->value.realval); |
526 | 7 | case t_integer:; |
527 | 7 | } |
528 | 7 | return 0; |
529 | 7 | } |
530 | | |
531 | | /* <num1> round <num2> */ |
532 | | int |
533 | | zround(i_ctx_t *i_ctx_p) |
534 | 37 | { |
535 | 37 | os_ptr op = osp; |
536 | | |
537 | 37 | check_op(1); |
538 | 36 | switch (r_type(op)) { |
539 | 1 | default: |
540 | 1 | return_op_typecheck(op); |
541 | 34 | case t_real: |
542 | 34 | op->value.realval = floor(op->value.realval + 0.5); |
543 | 35 | case t_integer:; |
544 | 36 | } |
545 | 35 | return 0; |
546 | 36 | } |
547 | | |
548 | | /* <num1> truncate <num2> */ |
549 | | int |
550 | | ztruncate(i_ctx_t *i_ctx_p) |
551 | 9 | { |
552 | 9 | os_ptr op = osp; |
553 | | |
554 | 9 | check_op(1); |
555 | 8 | switch (r_type(op)) { |
556 | 1 | default: |
557 | 1 | return_op_typecheck(op); |
558 | 7 | case t_real: |
559 | 7 | op->value.realval = |
560 | 7 | (op->value.realval < 0.0 ? |
561 | 0 | ceil(op->value.realval) : |
562 | 7 | floor(op->value.realval)); |
563 | 7 | case t_integer:; |
564 | 8 | } |
565 | 7 | return 0; |
566 | 8 | } |
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 | | }; |