double.c
1 //! @file double.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@algol68genie.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! LONG INT, LONG REAL and LONG BITS routines.
25
26 #include "a68g.h"
27
28 #if (A68G_LEVEL >= 3)
29
30 #include "a68g-genie.h"
31 #include "a68g-prelude.h"
32 #include "a68g-transput.h"
33 #include "a68g-mp.h"
34 #include "a68g-double.h"
35 #include "a68g-lib.h"
36 #include "a68g-numbers.h"
37
38 // 128-bit REAL support.
39
40 // Conversions.
41
42 DOUBLE_NUM_T double_int_to_double (NODE_T * p, DOUBLE_NUM_T z)
43 {
44 int neg = D_NEG (z);
45 if (neg) {
46 z = abs_double_int (z);
47 }
48 DOUBLE_NUM_T w, radix;
49 w.f = 0.0q;
50 set_lw (radix, RADIX);
51 DOUBLE_T weight = 1.0q;
52 while (!D_ZERO (z)) {
53 DOUBLE_NUM_T digit;
54 digit = double_udiv (p, M_LONG_INT, z, radix, 1);
55 w.f = w.f + LW (digit) * weight;
56 z = double_udiv (p, M_LONG_INT, z, radix, 0);
57 weight = weight * RADIX_Q;
58 }
59 if (neg) {
60 w.f = -w.f;
61 }
62 return w;
63 }
64
65 DOUBLE_NUM_T double_to_double_int (NODE_T * p, DOUBLE_NUM_T z)
66 {
67 // This routines looks a lot like "strtol".
68 BOOL_T negative = (BOOL_T) (z.f < 0);
69 z.f = fabs_double (trunc_double (z.f));
70 if (z.f > CONST_2_UP_112_Q) {
71 errno = EDOM;
72 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
73 }
74 DOUBLE_NUM_T sum, weight, radix;
75 set_lw (sum, 0);
76 set_lw (weight, 1);
77 set_lw (radix, RADIX);
78 while (z.f > 0) {
79 DOUBLE_NUM_T term, digit, quot, rest;
80 quot.f = trunc_double (z.f / RADIX_Q);
81 rest.f = z.f - quot.f * RADIX_Q;
82 z.f = quot.f;
83 set_lw (digit, (INT_T) (rest.f));
84 term = double_umul (p, M_LONG_INT, digit, weight);
85 sum = double_uadd (p, M_LONG_INT, sum, term);
86 if (z.f > 0.0q) {
87 weight = double_umul (p, M_LONG_INT, weight, radix);
88 }
89 }
90 if (negative) {
91 return neg_double_int (sum);
92 } else {
93 return sum;
94 }
95 }
96
97 //! @brief Value of LONG INT denotation
98
99 int string_to_double_int (NODE_T * p, A68G_LONG_INT * z, char *s)
100 {
101 while (IS_SPACE (s[0])) {
102 s++;
103 }
104 // Get the sign
105 int sign = (s[0] == '-' ? -1 : 1);
106 if (s[0] == '+' || s[0] == '-') {
107 s++;
108 }
109 int end = 0;
110 while (s[end] != '\0') {
111 end++;
112 }
113 DOUBLE_NUM_T weight, ten, sum;
114 set_lw (sum, 0);
115 set_lw (weight, 1);
116 set_lw (ten, 10);
117 for (int k = end - 1; k >= 0; k--) {
118 DOUBLE_NUM_T term;
119 int digit = s[k] - '0';
120 set_lw (term, digit);
121 term = double_umul (p, M_LONG_INT, term, weight);
122 sum = double_uadd (p, M_LONG_INT, sum, term);
123 weight = double_umul (p, M_LONG_INT, weight, ten);
124 }
125 if (sign == -1) {
126 HW (sum) = HW (sum) | D_SIGN;
127 }
128 VALUE (z) = sum;
129 STATUS (z) = INIT_MASK;
130 return A68G_TRUE;
131 }
132
133 //! @brief LONG BITS value of LONG BITS denotation
134
135 DOUBLE_NUM_T double_strtou (NODE_T * p, char *s)
136 {
137 errno = 0;
138 char *radix = NO_TEXT;
139 int base = (int) a68g_strtou (s, &radix, 10);
140 if (base < 2 || base > 16) {
141 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, base);
142 exit_genie (p, A68G_RUNTIME_ERROR);
143 }
144 DOUBLE_NUM_T z;
145 set_lw (z, 0x0);
146 if (radix != NO_TEXT && TO_UPPER (radix[0]) == TO_UPPER (RADIX_CHAR) && errno == 0) {
147 DOUBLE_NUM_T w;
148 char *q = radix;
149 while (q[0] != NULL_CHAR) {
150 q++;
151 }
152 set_lw (w, 1);
153 while ((--q) != radix) {
154 int digit = char_value (q[0]);
155 if (digit < 0 && digit >= base) {
156 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_LONG_BITS);
157 exit_genie (p, A68G_RUNTIME_ERROR);
158 } else {
159 DOUBLE_NUM_T v;
160 set_lw (v, digit);
161 v = double_umul (p, M_LONG_INT, v, w);
162 z = double_uadd (p, M_LONG_INT, z, v);
163 set_lw (v, base);
164 w = double_umul (p, M_LONG_INT, w, v);
165 }
166 }
167 } else {
168 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_LONG_BITS);
169 exit_genie (p, A68G_RUNTIME_ERROR);
170 }
171 return (z);
172 }
173
174 //! @brief OP LENG = (BITS) LONG BITS
175
176 void genie_lengthen_bits_to_double_bits (NODE_T * p)
177 {
178 A68G_BITS k;
179 POP_OBJECT (p, &k, A68G_BITS);
180 DOUBLE_NUM_T d;
181 LW (d) = VALUE (&k);
182 HW (d) = 0;
183 PUSH_VALUE (p, d, A68G_LONG_BITS);
184 }
185
186 //! @brief OP SHORTEN = (LONG BITS) BITS
187
188 void genie_shorten_double_bits_to_bits (NODE_T * p)
189 {
190 A68G_LONG_BITS k;
191 POP_OBJECT (p, &k, A68G_LONG_BITS);
192 DOUBLE_NUM_T j = VALUE (&k);
193 PRELUDE_ERROR (HW (j) != 0, p, ERROR_MATH, M_BITS);
194 PUSH_VALUE (p, LW (j), A68G_BITS);
195 }
196
197 //! @brief Convert to other radix, binary up to hexadecimal.
198
199 BOOL_T convert_radix_double (NODE_T * p, DOUBLE_NUM_T z, int radix, int width)
200 {
201 if (radix < 2 || radix > 16) {
202 radix = 16;
203 }
204 DOUBLE_NUM_T w, rad;
205 set_lw (rad, radix);
206 reset_transput_buffer (EDIT_BUFFER);
207 if (width > 0) {
208 while (width > 0) {
209 w = double_udiv (p, M_LONG_INT, z, rad, 1);
210 plusto_transput_buffer (p, digchar (LW (w)), EDIT_BUFFER);
211 width--;
212 z = double_udiv (p, M_LONG_INT, z, rad, 0);
213 }
214 return D_ZERO (z);
215 } else if (width == 0) {
216 do {
217 w = double_udiv (p, M_LONG_INT, z, rad, 1);
218 plusto_transput_buffer (p, digchar (LW (w)), EDIT_BUFFER);
219 z = double_udiv (p, M_LONG_INT, z, rad, 0);
220 }
221 while (!D_ZERO (z));
222 return A68G_TRUE;
223 } else {
224 return A68G_FALSE;
225 }
226 }
227
228 //! @brief OP LENG = (LONG INT) LONG REAL
229
230 void genie_widen_double_int_to_double (NODE_T * p)
231 {
232 A68G_DOUBLE *z = (A68G_DOUBLE *) STACK_TOP;
233 GENIE_UNIT (SUB (p));
234 VALUE (z) = double_int_to_double (p, VALUE (z));
235 }
236
237 //! @brief OP LENG = (REAL) LONG REAL
238
239 void genie_lengthen_real_to_double (NODE_T * p)
240 {
241 A68G_REAL z;
242 POP_OBJECT (p, &z, A68G_REAL);
243 REAL_T y = VALUE (&z);
244 if (a68g_isinf_real (y)) {
245 if (y == A68G_POSINF_REAL) {
246 genie_infinity_double (p);
247 } else {
248 genie_minus_infinity_double (p);
249 }
250 } else { // Convert REAL mantissa to 64-bit INT.
251 BOOL_T nega = (y < 0.0);
252 // RR standardize (v, before=1, after=A68G_REAL_DIG, expo=0);
253 DOUBLE_T v = (DOUBLE_T) fabs (y); int before = 1, after = A68G_REAL_DIG, expo = 0;
254 // REAL g = 10.0 ^ before, REAL h := g * .1;
255 DOUBLE_T g = ten_up_double (before); DOUBLE_T h = g * 0.1q;
256 // WHILE v >= g DO v *:= .1; p +:= 1 OD;
257 while (v >= g) {
258 v *= 0.1q;
259 expo++;
260 }
261 // (v /= 0.0 | WHILE v < h DO v *:= 10.0; p -:= 1 OD);
262 if (v != 0.0q) {
263 while (v < h) {
264 v *= 10.0q;
265 expo--;
266 }
267 }
268 // (v + .5 * .1 ^ after >= g | v := h; p +:= 1)
269 DOUBLE_T f = ten_up_double (-after);
270 if (v + 0.5q * f >= g) {
271 v = h;
272 expo++;
273 }
274 // END standardize
275 DOUBLE_NUM_T w;
276 set_lw (w, (INT_T) (((REAL_T) v) * ten_up (after)));
277 w = double_int_to_double (p, w);
278 w.f *= ten_up_double (expo - after);
279 if (nega) {
280 w.f = -w.f;
281 }
282 PUSH_VALUE (p, w, A68G_LONG_REAL);
283 }
284 }
285
286 //! @brief OP SHORTEN = (LONG REAL) REAL
287
288 void genie_shorten_double_to_real (NODE_T * p)
289 {
290 A68G_LONG_REAL z;
291 POP_OBJECT (p, &z, A68G_LONG_REAL);
292 REAL_T w = VALUE (&z).f;
293 PUSH_VALUE (p, w, A68G_REAL);
294 }
295
296 //! @brief Convert integer to multi-precison number.
297
298 MP_T *double_int_to_mp (NODE_T * p, MP_T * z, DOUBLE_NUM_T k, int digs)
299 {
300 int negative = D_NEG (k);
301 if (negative) {
302 k = neg_double_int (k);
303 }
304 DOUBLE_NUM_T radix;
305 set_lw (radix, MP_RADIX);
306 DOUBLE_NUM_T k2 = k;
307 int n = 0;
308 do {
309 k2 = double_udiv (p, M_LONG_INT, k2, radix, 0);
310 if (!D_ZERO (k2)) {
311 n++;
312 }
313 }
314 while (!D_ZERO (k2));
315 SET_MP_ZERO (z, digs);
316 MP_EXPONENT (z) = (MP_T) n;
317 for (int j = 1 + n; j >= 1; j--) {
318 DOUBLE_NUM_T term = double_udiv (p, M_LONG_INT, k, radix, 1);
319 MP_DIGIT (z, j) = (MP_T) LW (term);
320 k = double_udiv (p, M_LONG_INT, k, radix, 0);
321 }
322 MP_DIGIT (z, 1) = (negative ? -MP_DIGIT (z, 1) : MP_DIGIT (z, 1));
323 check_mp_exp (p, z);
324 return z;
325 }
326
327 //! @brief Convert multi-precision number to integer.
328
329 DOUBLE_NUM_T mp_to_double_int (NODE_T * p, MP_T * z, int digs)
330 {
331 // This routines looks a lot like "strtol".
332 int expo = (int) MP_EXPONENT (z);
333 DOUBLE_NUM_T sum, weight;
334 set_lw (sum, 0);
335 set_lw (weight, 1);
336 BOOL_T negative;
337 if (expo >= digs) {
338 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MOID (p));
339 exit_genie (p, A68G_RUNTIME_ERROR);
340 }
341 negative = (BOOL_T) (MP_DIGIT (z, 1) < 0);
342 if (negative) {
343 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
344 }
345 for (int j = 1 + expo; j >= 1; j--) {
346 DOUBLE_NUM_T term, digit, radix;
347 set_lw (digit, (MP_INT_T) MP_DIGIT (z, j));
348 term = double_umul (p, M_LONG_INT, digit, weight);
349 sum = double_uadd (p, M_LONG_INT, sum, term);
350 set_lw (radix, MP_RADIX);
351 weight = double_umul (p, M_LONG_INT, weight, radix);
352 }
353 if (negative) {
354 return neg_double_int (sum);
355 } else {
356 return sum;
357 }
358 }
359
360 //! @brief Convert real to multi-precison number.
361
362 MP_T *double_to_mp (NODE_T * p, MP_T * z, DOUBLE_T x, int prec, BOOL_T round, int digs)
363 {
364 SET_MP_ZERO (z, digs);
365 if (a68g_isinf_double (x)) {
366 if (x == A68G_POSINF_DOUBLE) {
367 MP_STATUS (z) = (PLUS_INF_MASK | INIT_MASK);
368 } else {
369 MP_STATUS (z) = (MINUS_INF_MASK | INIT_MASK);
370 }
371 return z;
372 }
373 if (x == 0.0q) {
374 return z;
375 }
376 // Small integers can be done better by int_to_mp.
377 if (ABS (x) < MP_RADIX && trunc_double (x) == x) {
378 return int_to_mp (p, z, (int) trunc_double (x), digs);
379 }
380 int sign_x = SIGN (x);
381 // Scale to [0, 0.1>.
382 DOUBLE_T a = ABS (x);
383 INT_T expo = (int) log10_double (a);
384 a /= ten_up_double (expo);
385 expo--;
386 if (a >= 1.0q) {
387 a /= 10.0q;
388 expo++;
389 }
390 // Transport digits of x to the mantissa of z.
391 int j = 1, sum = 0, weight = (MP_RADIX / 10), num = 0, lim = MIN (prec, A68G_DOUBLE_DIG), nines = 0;
392 for (int k = 0; k < lim && j <= digs && a != 0.0q; k++) {
393 DOUBLE_T u = a * 10.0q;
394 DOUBLE_T v = floor_double (u);
395 a = u - v;
396 num = (int) v;
397 if (num == 9) {
398 nines++;
399 } else {
400 nines = 0;
401 }
402 sum += weight * num;
403 weight /= 10;
404 if (weight < 1) {
405 MP_DIGIT (z, j++) = (MP_T) sum;
406 sum = 0;
407 weight = (MP_RADIX / 10);
408 }
409 }
410 // Store the last digits.
411 if (j <= digs) {
412 MP_DIGIT (z, j) = (MP_T) sum;
413 }
414 //
415 INT_T shift = 1 + expo - prec;
416 (void) align_mp (z, &expo, digs);
417 MP_EXPONENT (z) = (MP_T) expo;
418 // Round when requested by caller.
419 // Heuristic - round when at least half of the digits are trailing '9's.
420 // This avoids some surprises in REAL transput:
421 // "fixed (1.15, 0, 1)" would produce "1.1",
422 // "fixed (1.25, 0, 1)" would produce "1.3".
423 if (round && nines >= prec / 2) {
424 ADDR_T pop_sp = A68G_SP;
425 MP_T *t = nil_mp (p, digs);
426 ten_up_mp (p, t, shift, digs);
427 add_mp (p, z, z, t, digs);
428 A68G_SP = pop_sp;
429 }
430 //
431 MP_DIGIT (z, 1) *= sign_x;
432 check_mp_exp (p, z);
433 return z;
434 }
435
436 //! @brief Convert multi-precision number to real.
437
438 DOUBLE_T mp_to_double (NODE_T * p, MP_T * z, int digs)
439 {
440 // This routine looks a lot like "strtod".
441 if (PLUS_INF_MP (z)) {
442 return A68G_POSINF_DOUBLE;
443 }
444 if (MINUS_INF_MP (z)) {
445 return A68G_MININF_DOUBLE;
446 }
447 if (MP_EXPONENT (z) * (MP_T) LOG_MP_RADIX <= (MP_T) A68G_DOUBLE_MIN_EXP) {
448 return 0.0q;
449 } else {
450 DOUBLE_T weight = ten_up_double ((int) (MP_EXPONENT (z) * LOG_MP_RADIX));
451 int lim = MIN (digs, MP_MAX_DIGITS);
452 DOUBLE_T terms[1 + MP_MAX_DIGITS];
453 for (int k = 1; k <= lim; k++) {
454 terms[k] = ABS (MP_DIGIT (z, k)) * weight;
455 weight /= MP_RADIX;
456 }
457 // Sum terms from small to large.
458 DOUBLE_T sum = 0;
459 for (int k = lim; k >= 1; k--) {
460 sum += terms[k];
461 }
462 CHECK_DOUBLE_REAL (p, sum);
463 return MP_DIGIT (z, 1) >= 0 ? sum : -sum;
464 }
465 }
466
467 DOUBLE_T inverf_double (DOUBLE_T z)
468 {
469 if (fabs_double (z) >= 1.0q) {
470 errno = EDOM;
471 return z;
472 } else {
473 // Newton-Raphson.
474 DOUBLE_T f = sqrt_double (M_PIq) / 2, g, x = z;
475 int its = 10;
476 x = dble (a68g_inverf_real ((REAL_T) x)).f;
477 do {
478 g = x;
479 x -= f * (erf_double (x) - z) / exp_double (-(x * x));
480 } while (its-- > 0 && errno == 0 && fabs_double (x - g) > (3 * A68G_DOUBLE_EPS));
481 return x;
482 }
483 }
484
485 //! @brief OP LENG = (LONG REAL) LONG LONG REAL
486
487 void genie_lengthen_double_to_mp (NODE_T * p)
488 {
489 int digs = DIGITS (M_LONG_LONG_REAL);
490 A68G_LONG_REAL x;
491 POP_OBJECT (p, &x, A68G_LONG_REAL);
492 MP_T *z = nil_mp (p, digs);
493 (void) double_to_mp (p, z, VALUE (&x).f, A68G_DOUBLE_DIG, A68G_FALSE, digs);
494 }
495
496 //! @brief OP SHORTEN = (LONG LONG REAL) LONG REAL
497
498 void genie_shorten_mp_to_double (NODE_T * p)
499 {
500 MOID_T *mode = LHS_MODE (p);
501 int digs = DIGITS (mode), size = SIZE (mode);
502 DOUBLE_NUM_T d;
503 DECREMENT_STACK_POINTER (p, size);
504 MP_T *z = (MP_T *) STACK_TOP;
505 d.f = mp_to_double (p, z, digs);
506 PUSH_VALUE (p, d, A68G_LONG_REAL);
507 }
508
509 //! @brief OP SHORTEN = (LONG LONG COMPLEX) LONG COMPLEX
510
511 void genie_shorten_long_mp_complex_to_double_compl (NODE_T * p)
512 {
513 int digs = DIGITS (M_LONG_LONG_REAL), size = SIZE (M_LONG_LONG_REAL);
514 MP_T *b = (MP_T *) STACK_OFFSET (-size);
515 MP_T *a = (MP_T *) STACK_OFFSET (-2 * size);
516 DECREMENT_STACK_POINTER (p, 2 * size);
517 DOUBLE_NUM_T u, v;
518 u.f = mp_to_double (p, a, digs);
519 v.f = mp_to_double (p, b, digs);
520 PUSH_VALUE (p, u, A68G_LONG_REAL);
521 PUSH_VALUE (p, v, A68G_LONG_REAL);
522 }
523
524 //! @brief OP LENG = (LONG INT) LONG LONG INT
525
526 void genie_lengthen_double_int_to_mp (NODE_T * p)
527 {
528 int digs = DIGITS (M_LONG_LONG_INT);
529 A68G_LONG_INT k;
530 POP_OBJECT (p, &k, A68G_LONG_INT);
531 MP_T *z = nil_mp (p, digs);
532 (void) double_int_to_mp (p, z, VALUE (&k), digs);
533 MP_STATUS (z) = (MP_T) INIT_MASK;
534 }
535
536 //! @brief OP SHORTEN = (LONG LONG INT) LONG INT
537
538 void genie_shorten_mp_to_double_int (NODE_T * p)
539 {
540 MOID_T *mode = LHS_MODE (p);
541 int digs = DIGITS (mode), size = SIZE (mode);
542 DECREMENT_STACK_POINTER (p, size);
543 MP_T *z = (MP_T *) STACK_TOP;
544 MP_STATUS (z) = (MP_T) INIT_MASK;
545 PUSH_VALUE (p, mp_to_double_int (p, z, digs), A68G_LONG_INT);
546 }
547
548 //! @brief OP LENG = (INT) LONG INT
549
550 void genie_lengthen_int_to_double_int (NODE_T * p)
551 {
552 A68G_INT k;
553 POP_OBJECT (p, &k, A68G_INT);
554 INT_T v = VALUE (&k);
555 DOUBLE_NUM_T d;
556 if (v >= 0) {
557 LW (d) = v;
558 HW (d) = 0;
559 } else {
560 LW (d) = -v;
561 HW (d) = D_SIGN;
562 }
563 PUSH_VALUE (p, d, A68G_LONG_INT);
564 }
565
566 //! @brief OP SHORTEN = (LONG INT) INT
567
568 void genie_shorten_long_int_to_int (NODE_T * p)
569 {
570 A68G_LONG_INT k;
571 POP_OBJECT (p, &k, A68G_LONG_INT);
572 DOUBLE_NUM_T j = VALUE (&k);
573 PRELUDE_ERROR (HW (j) != 0 && HW (j) != D_SIGN, p, ERROR_MATH, M_INT);
574 PRELUDE_ERROR (LW (j) & D_SIGN, p, ERROR_MATH, M_INT);
575 if (D_NEG (j)) {
576 PUSH_VALUE (p, -LW (j), A68G_INT);
577 } else {
578 PUSH_VALUE (p, LW (j), A68G_INT);
579 }
580 }
581
582 // Constants.
583
584 //! @brief PROC long max int = LONG INT
585
586 void genie_double_max_int (NODE_T * p)
587 {
588 DOUBLE_NUM_T d;
589 HW (d) = 0x7fffffffffffffffLL;
590 LW (d) = 0xffffffffffffffffLL;
591 PUSH_VALUE (p, d, A68G_LONG_INT);
592 }
593
594 //! @brief PROC long max bits = LONG BITS
595
596 void genie_double_max_bits (NODE_T * p)
597 {
598 DOUBLE_NUM_T d;
599 HW (d) = 0xffffffffffffffffLL;
600 LW (d) = 0xffffffffffffffffLL;
601 PUSH_VALUE (p, d, A68G_LONG_INT);
602 }
603
604 //! @brief LONG REAL max long real
605
606 void genie_double_max_real (NODE_T * p)
607 {
608 DOUBLE_NUM_T d;
609 d.f = A68G_DOUBLE_MAX;
610 PUSH_VALUE (p, d, A68G_LONG_REAL);
611 }
612
613 //! @brief LONG REAL min long real
614
615 void genie_double_min_real (NODE_T * p)
616 {
617 DOUBLE_NUM_T d;
618 d.f = A68G_DOUBLE_MIN;
619 PUSH_VALUE (p, d, A68G_LONG_REAL);
620 }
621
622 //! @brief LONG REAL small long real
623
624 void genie_double_small_real (NODE_T * p)
625 {
626 DOUBLE_NUM_T d;
627 d.f = A68G_DOUBLE_EPS;
628 PUSH_VALUE (p, d, A68G_LONG_REAL);
629 }
630
631 //! @brief PROC long pi = LON REAL
632
633 void genie_pi_double (NODE_T * p)
634 {
635 DOUBLE_NUM_T w;
636 w.f = M_PIq;
637 PUSH_VALUE (p, w, A68G_LONG_INT);
638 }
639
640 // MONADs and DYADs
641
642 //! @brief OP SIGN = (LONG INT) INT
643
644 void genie_sign_double_int (NODE_T * p)
645 {
646 A68G_LONG_INT k;
647 POP_OBJECT (p, &k, A68G_LONG_INT);
648 PUSH_VALUE (p, sign_double_int (VALUE (&k)), A68G_INT);
649 }
650
651 //! @brief OP ABS = (LONG INT) LONG INT
652
653 void genie_abs_double_int (NODE_T * p)
654 {
655 A68G_LONG_INT *k;
656 POP_OPERAND_ADDRESS (p, k, A68G_LONG_INT);
657 VALUE (k) = abs_double_int (VALUE (k));
658 }
659
660 //! @brief OP ODD = (LONG INT) BOOL
661
662 void genie_odd_double_int (NODE_T * p)
663 {
664 A68G_LONG_INT j;
665 POP_OBJECT (p, &j, A68G_LONG_INT);
666 DOUBLE_NUM_T w = abs_double_int (VALUE (&j));
667 if (LW (w) & 0x1) {
668 PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
669 } else {
670 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
671 }
672 }
673
674 //! @brief OP - = (LONG INT) LONG INT
675
676 void genie_minus_double_int (NODE_T * p)
677 {
678 A68G_LONG_INT *k;
679 POP_OPERAND_ADDRESS (p, k, A68G_LONG_INT);
680 VALUE (k) = neg_double_int (VALUE (k));
681 }
682
683 //! @brief OP + = (LONG INT, LONG INT) LONG INT
684
685 void genie_add_double_int (NODE_T * p)
686 {
687 A68G_LONG_INT i, j;
688 POP_OBJECT (p, &j, A68G_LONG_INT);
689 POP_OBJECT (p, &i, A68G_LONG_INT);
690 PUSH_VALUE (p, double_sadd (p, VALUE (&i), VALUE (&j)), A68G_LONG_INT);
691 }
692
693 //! @brief OP - = (LONG INT, LONG INT) LONG INT
694
695 void genie_sub_double_int (NODE_T * p)
696 {
697 A68G_LONG_INT i, j;
698 POP_OBJECT (p, &j, A68G_LONG_INT);
699 POP_OBJECT (p, &i, A68G_LONG_INT);
700 PUSH_VALUE (p, double_ssub (p, VALUE (&i), VALUE (&j)), A68G_LONG_INT);
701 }
702
703 //! @brief OP * = (LONG INT, LONG INT) LONG INT
704
705 void genie_mul_double_int (NODE_T * p)
706 {
707 A68G_LONG_INT i, j;
708 POP_OBJECT (p, &j, A68G_LONG_INT);
709 POP_OBJECT (p, &i, A68G_LONG_INT);
710 PUSH_VALUE (p, double_smul (p, VALUE (&i), VALUE (&j)), A68G_LONG_INT);
711 }
712
713 //! @brief OP / = (LONG INT, LONG INT) LONG INT
714
715 void genie_over_double_int (NODE_T * p)
716 {
717 A68G_LONG_INT i, j;
718 POP_OBJECT (p, &j, A68G_LONG_INT);
719 POP_OBJECT (p, &i, A68G_LONG_INT);
720 PRELUDE_ERROR (D_ZERO (VALUE (&j)), p, ERROR_DIVISION_BY_ZERO, M_LONG_INT);
721 PUSH_VALUE (p, double_sdiv (p, VALUE (&i), VALUE (&j), 0), A68G_LONG_INT);
722 }
723
724 //! @brief OP MOD = (LONG INT, LONG INT) LONG INT
725
726 void genie_mod_double_int (NODE_T * p)
727 {
728 A68G_LONG_INT i, j;
729 POP_OBJECT (p, &j, A68G_LONG_INT);
730 POP_OBJECT (p, &i, A68G_LONG_INT);
731 PRELUDE_ERROR (D_ZERO (VALUE (&j)), p, ERROR_DIVISION_BY_ZERO, M_LONG_INT);
732 PUSH_VALUE (p, double_sdiv (p, VALUE (&i), VALUE (&j), 1), A68G_LONG_INT);
733 }
734
735 //! @brief OP / = (LONG INT, LONG INT) LONG REAL
736
737 void genie_div_double_int (NODE_T * p)
738 {
739 A68G_LONG_INT i, j;
740 POP_OBJECT (p, &j, A68G_LONG_INT);
741 POP_OBJECT (p, &i, A68G_LONG_INT);
742 PRELUDE_ERROR (D_ZERO (VALUE (&j)), p, ERROR_DIVISION_BY_ZERO, M_LONG_INT);
743 DOUBLE_NUM_T u, v, w;
744 v = double_int_to_double (p, VALUE (&j));
745 u = double_int_to_double (p, VALUE (&i));
746 w.f = u.f / v.f;
747 PUSH_VALUE (p, w, A68G_LONG_REAL);
748 }
749
750 //! @brief OP ** = (LONG INT, INT) INT
751
752 void genie_pow_double_int_int (NODE_T * p)
753 {
754 A68G_LONG_INT i; A68G_INT j;
755 POP_OBJECT (p, &j, A68G_INT);
756 PRELUDE_ERROR (VALUE (&j) < 0, p, ERROR_EXPONENT_INVALID, M_INT);
757 POP_OBJECT (p, &i, A68G_LONG_INT);
758 DOUBLE_NUM_T mult = VALUE (&i), prod;
759 set_lw (prod, 1);
760 UNSIGNED_T top = (UNSIGNED_T) VALUE (&j), expo = 1;
761 while (expo <= top) {
762 if (expo & top) {
763 prod = double_smul (p, prod, mult);
764 }
765 expo <<= 1;
766 if (expo <= top) {
767 mult = double_smul (p, mult, mult);
768 }
769 }
770 PUSH_VALUE (p, prod, A68G_LONG_INT);
771 }
772
773 //! @brief OP - = (LONG REAL) LONG REAL
774
775 void genie_minus_double (NODE_T * p)
776 {
777 A68G_LONG_REAL *u;
778 POP_OPERAND_ADDRESS (p, u, A68G_LONG_REAL);
779 VALUE (u).f = -(VALUE (u).f);
780 }
781
782 //! @brief OP ABS = (LONG REAL) LONG REAL
783
784 void genie_abs_double (NODE_T * p)
785 {
786 A68G_LONG_REAL *u;
787 POP_OPERAND_ADDRESS (p, u, A68G_LONG_REAL);
788 VALUE (u).f = fabs_double (VALUE (u).f);
789 }
790
791 //! @brief OP SIGN = (LONG REAL) INT
792
793 void genie_sign_double (NODE_T * p)
794 {
795 A68G_LONG_REAL u;
796 POP_OBJECT (p, &u, A68G_LONG_REAL);
797 PUSH_VALUE (p, sign_double (VALUE (&u)), A68G_INT);
798 }
799
800 //! @brief OP ** = (LONG REAL, INT) INT
801
802 void genie_pow_double_int (NODE_T * p)
803 {
804 A68G_INT j;
805 POP_OBJECT (p, &j, A68G_INT);
806 INT_T top = (INT_T) VALUE (&j);
807 A68G_LONG_REAL z;
808 POP_OBJECT (p, &z, A68G_LONG_INT);
809 DOUBLE_NUM_T mult, prod;
810 prod.f = 1.0q;
811 mult.f = VALUE (&z).f;
812 int negative;
813 if (top < 0) {
814 top = -top;
815 negative = A68G_TRUE;
816 } else {
817 negative = A68G_FALSE;
818 }
819 UNSIGNED_T expo = 1;
820 while (expo <= top) {
821 if (expo & top) {
822 prod.f = prod.f * mult.f;
823 CHECK_DOUBLE_REAL (p, prod.f);
824 }
825 expo <<= 1;
826 if (expo <= top) {
827 mult.f = mult.f * mult.f;
828 CHECK_DOUBLE_REAL (p, mult.f);
829 }
830 }
831 if (negative) {
832 prod.f = 1.0q / prod.f;
833 }
834 PUSH_VALUE (p, prod, A68G_LONG_REAL);
835 }
836
837 //! @brief OP ** = (LONG REAL, LONG REAL) LONG REAL
838
839 void genie_pow_double (NODE_T * p)
840 {
841 A68G_LONG_REAL x, y;
842 POP_OBJECT (p, &y, A68G_LONG_REAL);
843 POP_OBJECT (p, &x, A68G_LONG_REAL);
844 errno = 0;
845 PRELUDE_ERROR (VALUE (&x).f < 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
846 DOUBLE_T z = 0.0q;
847 if (VALUE (&x).f == 0.0q) {
848 if (VALUE (&y).f < 0.0q) {
849 errno = ERANGE;
850 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
851 } else {
852 z = (VALUE (&y).f == 0.0q ? 1.0q : 0.0q);
853 }
854 } else {
855 z = exp_double (VALUE (&y).f * log_double (VALUE (&x).f));
856 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
857 }
858 PUSH_VALUE (p, dble (z), A68G_LONG_REAL);
859 }
860
861 //! @brief OP + = (LONG REAL, LONG REAL) LONG REAL
862
863 void genie_add_double (NODE_T * p)
864 {
865 A68G_LONG_REAL u, v;
866 POP_OBJECT (p, &v, A68G_LONG_REAL);
867 POP_OBJECT (p, &u, A68G_LONG_REAL);
868 DOUBLE_NUM_T w;
869 w.f = VALUE (&u).f + VALUE (&v).f;
870 CHECK_DOUBLE_REAL (p, w.f);
871 PUSH_VALUE (p, w, A68G_LONG_REAL);
872 }
873
874 //! @brief OP - = (LONG REAL, LONG REAL) LONG REAL
875
876 void genie_sub_double (NODE_T * p)
877 {
878 A68G_LONG_REAL u, v;
879 POP_OBJECT (p, &v, A68G_LONG_REAL);
880 POP_OBJECT (p, &u, A68G_LONG_REAL);
881 DOUBLE_NUM_T w;
882 w.f = VALUE (&u).f - VALUE (&v).f;
883 CHECK_DOUBLE_REAL (p, w.f);
884 PUSH_VALUE (p, w, A68G_LONG_REAL);
885 }
886
887 //! @brief OP * = (LONG REAL, LONG REAL) LONG REAL
888
889 void genie_mul_double (NODE_T * p)
890 {
891 A68G_LONG_REAL u, v;
892 POP_OBJECT (p, &v, A68G_LONG_REAL);
893 POP_OBJECT (p, &u, A68G_LONG_REAL);
894 DOUBLE_NUM_T w;
895 w.f = VALUE (&u).f * VALUE (&v).f;
896 CHECK_DOUBLE_REAL (p, w.f);
897 PUSH_VALUE (p, w, A68G_LONG_REAL);
898 }
899
900 //! @brief OP / = (LONG REAL, LONG REAL) LONG REAL
901
902 void genie_over_double (NODE_T * p)
903 {
904 A68G_LONG_REAL u, v;
905 POP_OBJECT (p, &v, A68G_LONG_REAL);
906 POP_OBJECT (p, &u, A68G_LONG_REAL);
907 PRELUDE_ERROR (VALUE (&v).f == 0.0q, p, ERROR_DIVISION_BY_ZERO, M_LONG_REAL);
908 DOUBLE_NUM_T w;
909 w.f = VALUE (&u).f / VALUE (&v).f;
910 PUSH_VALUE (p, w, A68G_LONG_REAL);
911 }
912
913 //! @brief OP +:= = (REF LONG INT, LONG INT) REF LONG INT
914
915 void genie_plusab_double_int (NODE_T * p)
916 {
917 genie_f_and_becomes (p, M_REF_LONG_INT, genie_add_double_int);
918 }
919
920 //! @brief OP -:= = (REF LONG INT, LONG INT) REF LONG INT
921
922 void genie_minusab_double_int (NODE_T * p)
923 {
924 genie_f_and_becomes (p, M_REF_LONG_INT, genie_sub_double_int);
925 }
926
927 //! @brief OP *:= = (REF LONG INT, LONG INT) REF LONG INT
928
929 void genie_timesab_double_int (NODE_T * p)
930 {
931 genie_f_and_becomes (p, M_REF_LONG_INT, genie_mul_double_int);
932 }
933
934 //! @brief OP %:= = (REF LONG INT, LONG INT) REF LONG INT
935
936 void genie_overab_double_int (NODE_T * p)
937 {
938 genie_f_and_becomes (p, M_REF_LONG_INT, genie_over_double_int);
939 }
940
941 //! @brief OP %*:= = (REF LONG INT, LONG INT) REF LONG INT
942
943 void genie_modab_double_int (NODE_T * p)
944 {
945 genie_f_and_becomes (p, M_REF_LONG_INT, genie_mod_double_int);
946 }
947
948 //! @brief OP +:= = (REF LONG REAL, LONG REAL) REF LONG REAL
949
950 void genie_plusab_double (NODE_T * p)
951 {
952 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_add_double);
953 }
954
955 //! @brief OP -:= = (REF LONG REAL, LONG REAL) REF LONG REAL
956
957 void genie_minusab_double (NODE_T * p)
958 {
959 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_sub_double);
960 }
961
962 //! @brief OP *:= = (REF LONG REAL, LONG REAL) REF LONG REAL
963
964 void genie_timesab_double (NODE_T * p)
965 {
966 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_mul_double);
967 }
968
969 //! @brief OP /:= = (REF LONG REAL, LONG REAL) REF LONG REAL
970
971 void genie_divab_double (NODE_T * p)
972 {
973 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_over_double);
974 }
975
976 // OP (LONG INT, LONG INT) BOOL.
977
978 #define A68G_CMP_INT(n, OP)\
979 void n (NODE_T * p) {\
980 A68G_LONG_INT i, j;\
981 POP_OBJECT (p, &j, A68G_LONG_INT);\
982 POP_OBJECT (p, &i, A68G_LONG_INT);\
983 DOUBLE_NUM_T w = double_ssub (p, VALUE (&i), VALUE (&j));\
984 int k = sign_double_int (w);\
985 PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
986 }
987
988 A68G_CMP_INT (genie_eq_double_int, ==);
989 A68G_CMP_INT (genie_ne_double_int, !=);
990 A68G_CMP_INT (genie_lt_double_int, <);
991 A68G_CMP_INT (genie_gt_double_int, >);
992 A68G_CMP_INT (genie_le_double_int, <=);
993 A68G_CMP_INT (genie_ge_double_int, >=);
994
995 // OP (LONG REAL, LONG REAL) BOOL.
996 #define A68G_CMP_REAL(n, OP)\
997 void n (NODE_T * p) {\
998 A68G_LONG_REAL i, j;\
999 POP_OBJECT (p, &j, A68G_LONG_REAL);\
1000 POP_OBJECT (p, &i, A68G_LONG_REAL);\
1001 PUSH_VALUE (p, (BOOL_T) (VALUE (&i).f OP VALUE (&j).f), A68G_BOOL);\
1002 }
1003
1004 A68G_CMP_REAL (genie_eq_double, ==);
1005 A68G_CMP_REAL (genie_ne_double, !=);
1006 A68G_CMP_REAL (genie_lt_double, <);
1007 A68G_CMP_REAL (genie_gt_double, >);
1008 A68G_CMP_REAL (genie_le_double, <=);
1009 A68G_CMP_REAL (genie_ge_double, >=);
1010
1011 //! @brief OP NOT = (LONG BITS) LONG BITS
1012
1013 void genie_not_double_bits (NODE_T * p)
1014 {
1015 A68G_LONG_BITS i;
1016 POP_OBJECT (p, &i, A68G_LONG_BITS);
1017 DOUBLE_NUM_T w;
1018 HW (w) = ~HW (VALUE (&i));
1019 LW (w) = ~LW (VALUE (&i));
1020 PUSH_VALUE (p, w, A68G_LONG_BITS);
1021 }
1022
1023 //! @brief OP = = (LONG BITS, LONG BITS) BOOL.
1024
1025 void genie_eq_double_bits (NODE_T * p)
1026 {
1027 A68G_LONG_BITS i, j;
1028 POP_OBJECT (p, &j, A68G_LONG_BITS);
1029 POP_OBJECT (p, &i, A68G_LONG_BITS);
1030 BOOL_T u = HW (VALUE (&i)) == HW (VALUE (&j));
1031 BOOL_T v = LW (VALUE (&i)) == LW (VALUE (&j));
1032 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1033 }
1034
1035 //! @brief OP ~= = (LONG BITS, LONG BITS) BOOL.
1036
1037 void genie_ne_double_bits (NODE_T * p)
1038 {
1039 A68G_LONG_BITS i, j;
1040 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i ~= j) == ~ (i = j)
1041 POP_OBJECT (p, &i, A68G_LONG_BITS);
1042 BOOL_T u = HW (VALUE (&i)) == HW (VALUE (&j));
1043 BOOL_T v = LW (VALUE (&i)) == LW (VALUE (&j));
1044 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_FALSE : A68G_TRUE), A68G_BOOL);
1045 }
1046
1047 //! @brief OP <= = (LONG BITS, LONG BITS) BOOL
1048
1049 void genie_le_double_bits (NODE_T * p)
1050 {
1051 A68G_LONG_BITS i, j;
1052 POP_OBJECT (p, &j, A68G_LONG_BITS);
1053 POP_OBJECT (p, &i, A68G_LONG_BITS);
1054 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&j));
1055 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&j));
1056 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1057 }
1058
1059 //! @brief OP > = (LONG BITS, LONG BITS) BOOL
1060
1061 void genie_gt_double_bits (NODE_T * p)
1062 {
1063 A68G_LONG_BITS i, j;
1064 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i > j) == ! (i <= j)
1065 POP_OBJECT (p, &i, A68G_LONG_BITS);
1066 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&j));
1067 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&j));
1068 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_FALSE : A68G_TRUE), A68G_BOOL);
1069 }
1070
1071 //! @brief OP >= = (LONG BITS, LONG BITS) BOOL
1072
1073 void genie_ge_double_bits (NODE_T * p)
1074 {
1075 A68G_LONG_BITS i, j;
1076 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i >= j) == (j <= i)
1077 POP_OBJECT (p, &i, A68G_LONG_BITS);
1078 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&i));
1079 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&i));
1080 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1081 }
1082
1083 //! @brief OP < = (LONG BITS, LONG BITS) BOOL
1084
1085 void genie_lt_double_bits (NODE_T * p)
1086 {
1087 A68G_LONG_BITS i, j;
1088 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i < j) == ! (i >= j)
1089 POP_OBJECT (p, &i, A68G_LONG_BITS);
1090 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&i));
1091 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&i));
1092 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_FALSE : A68G_TRUE), A68G_BOOL);
1093 }
1094
1095 //! @brief PROC long bits pack = ([] BOOL) BITS
1096
1097 void genie_double_bits_pack (NODE_T * p)
1098 {
1099 A68G_REF z;
1100 POP_REF (p, &z);
1101 CHECK_REF (p, z, M_ROW_BOOL);
1102 A68G_ARRAY *arr; A68G_TUPLE *tup;
1103 GET_DESCRIPTOR (arr, tup, &z);
1104 size_t size = ROW_SIZE (tup);
1105 PRELUDE_ERROR (size < 0 || size > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_ROW_BOOL);
1106 DOUBLE_NUM_T w;
1107 set_lw (w, 0x0);
1108 if (ROW_SIZE (tup) > 0) {
1109 UNSIGNED_T bit = 0x0;
1110 BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
1111 int n = 0;
1112 for (int k = UPB (tup); k >= LWB (tup); k--) {
1113 A68G_BOOL *boo = (A68G_BOOL *) & (base[INDEX_1_DIM (arr, tup, k)]);
1114 CHECK_INIT (p, INITIALISED (boo), M_BOOL);
1115 if (n == 0 || n == A68G_BITS_WIDTH) {
1116 bit = 0x1;
1117 }
1118 if (VALUE (boo)) {
1119 if (n < A68G_BITS_WIDTH) {
1120 LW (w) |= bit;
1121 } else {
1122 HW (w) |= bit;
1123 };
1124 }
1125 n++;
1126 bit <<= 1;
1127 }
1128 }
1129 PUSH_VALUE (p, w, A68G_LONG_BITS);
1130 }
1131
1132 //! @brief OP AND = (LONG BITS, LONG BITS) LONG BITS
1133
1134 void genie_and_double_bits (NODE_T * p)
1135 {
1136 A68G_LONG_BITS i, j;
1137 POP_OBJECT (p, &j, A68G_LONG_BITS);
1138 POP_OBJECT (p, &i, A68G_LONG_BITS);
1139 DOUBLE_NUM_T w;
1140 HW (w) = HW (VALUE (&i)) & HW (VALUE (&j));
1141 LW (w) = LW (VALUE (&i)) & LW (VALUE (&j));
1142 PUSH_VALUE (p, w, A68G_LONG_BITS);
1143 }
1144
1145 //! @brief OP OR = (LONG BITS, LONG BITS) LONG BITS
1146
1147 void genie_or_double_bits (NODE_T * p)
1148 {
1149 A68G_LONG_BITS i, j;
1150 POP_OBJECT (p, &j, A68G_LONG_BITS);
1151 POP_OBJECT (p, &i, A68G_LONG_BITS);
1152 DOUBLE_NUM_T w;
1153 HW (w) = HW (VALUE (&i)) | HW (VALUE (&j));
1154 LW (w) = LW (VALUE (&i)) | LW (VALUE (&j));
1155 PUSH_VALUE (p, w, A68G_LONG_BITS);
1156 }
1157
1158 //! @brief OP XOR = (LONG BITS, LONG BITS) LONG BITS
1159
1160 void genie_xor_double_bits (NODE_T * p)
1161 {
1162 A68G_LONG_BITS i, j;
1163 POP_OBJECT (p, &j, A68G_LONG_BITS);
1164 POP_OBJECT (p, &i, A68G_LONG_BITS);
1165 DOUBLE_NUM_T w;
1166 HW (w) = HW (VALUE (&i)) ^ HW (VALUE (&j));
1167 LW (w) = LW (VALUE (&i)) ^ LW (VALUE (&j));
1168 PUSH_VALUE (p, w, A68G_LONG_BITS);
1169 }
1170
1171 //! @brief OP + = (LONG BITS, LONG BITS) LONG BITS
1172
1173 void genie_add_double_bits (NODE_T * p)
1174 {
1175 A68G_LONG_BITS i, j;
1176 POP_OBJECT (p, &j, A68G_LONG_BITS);
1177 POP_OBJECT (p, &i, A68G_LONG_BITS);
1178 DOUBLE_NUM_T w;
1179 add_double (p, M_LONG_BITS, w, VALUE (&i), VALUE (&j));
1180 PUSH_VALUE (p, w, A68G_LONG_BITS);
1181 }
1182
1183 //! @brief OP - = (LONG BITS, LONG BITS) LONG BITS
1184
1185 void genie_sub_double_bits (NODE_T * p)
1186 {
1187 A68G_LONG_BITS i, j;
1188 POP_OBJECT (p, &j, A68G_LONG_BITS);
1189 POP_OBJECT (p, &i, A68G_LONG_BITS);
1190 DOUBLE_NUM_T w;
1191 sub_double (p, M_LONG_BITS, w, VALUE (&i), VALUE (&j));
1192 PUSH_VALUE (p, w, A68G_LONG_BITS);
1193 }
1194
1195 //! @brief OP * = (LONG BITS, LONG BITS) LONG BITS
1196
1197 void genie_times_double_bits (NODE_T * p)
1198 {
1199 A68G_LONG_BITS i, j;
1200 POP_OBJECT (p, &j, A68G_LONG_BITS);
1201 POP_OBJECT (p, &i, A68G_LONG_BITS);
1202 DOUBLE_NUM_T w = double_umul (p, M_LONG_BITS, VALUE (&i), VALUE (&j));
1203 PUSH_VALUE (p, w, A68G_LONG_BITS);
1204 }
1205
1206 //! @brief OP OVER = (LONG BITS, LONG BITS) LONG BITS
1207
1208 void genie_over_double_bits (NODE_T * p)
1209 {
1210 A68G_LONG_BITS i, j;
1211 POP_OBJECT (p, &j, A68G_LONG_BITS);
1212 POP_OBJECT (p, &i, A68G_LONG_BITS);
1213 DOUBLE_NUM_T w = double_udiv (p, M_LONG_BITS, VALUE (&i), VALUE (&j), 0);
1214 PUSH_VALUE (p, w, A68G_LONG_BITS);
1215 }
1216
1217 //! @brief OP MOD = (LONG BITS, LONG BITS) LONG BITS
1218
1219 void genie_mod_double_bits (NODE_T * p)
1220 {
1221 A68G_LONG_BITS i, j;
1222 DOUBLE_NUM_T w;
1223 POP_OBJECT (p, &j, A68G_LONG_BITS);
1224 POP_OBJECT (p, &i, A68G_LONG_BITS);
1225 w = double_udiv (p, M_LONG_BITS, VALUE (&i), VALUE (&j), 1);
1226 PUSH_VALUE (p, w, A68G_LONG_BITS);
1227 }
1228
1229 //! @brief OP ELEM = (INT, LONG BITS) BOOL
1230
1231 void genie_elem_double_bits (NODE_T * p)
1232 {
1233 A68G_LONG_BITS j; A68G_INT i;
1234 POP_OBJECT (p, &j, A68G_LONG_BITS);
1235 POP_OBJECT (p, &i, A68G_INT);
1236 int k = VALUE (&i);
1237 PRELUDE_ERROR (k < 1 || k > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1238 UNSIGNED_T mask = 0x1, *w;
1239 if (k <= A68G_BITS_WIDTH) {
1240 w = &(HW (VALUE (&j)));
1241 } else {
1242 w = &(LW (VALUE (&j)));
1243 k -= A68G_BITS_WIDTH;
1244 }
1245 for (int n = 0; n < A68G_BITS_WIDTH - k; n++) {
1246 mask = mask << 1;
1247 }
1248 PUSH_VALUE (p, (BOOL_T) ((*w & mask) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1249 }
1250
1251 //! @brief OP SET = (INT, LONG BITS) LONG BITS
1252
1253 void genie_set_double_bits (NODE_T * p)
1254 {
1255 A68G_LONG_BITS j; A68G_INT i;
1256 POP_OBJECT (p, &j, A68G_LONG_BITS);
1257 POP_OBJECT (p, &i, A68G_INT);
1258 int k = VALUE (&i);
1259 PRELUDE_ERROR (k < 1 || k > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1260 UNSIGNED_T mask = 0x1, *w;
1261 if (k <= A68G_BITS_WIDTH) {
1262 w = &(HW (VALUE (&j)));
1263 } else {
1264 w = &(LW (VALUE (&j)));
1265 k -= A68G_BITS_WIDTH;
1266 }
1267 for (int n = 0; n < A68G_BITS_WIDTH - k; n++) {
1268 mask = mask << 1;
1269 }
1270 (*w) |= mask;
1271 PUSH_OBJECT (p, j, A68G_LONG_BITS);
1272 }
1273
1274 //! @brief OP CLEAR = (INT, LONG BITS) LONG BITS
1275
1276 void genie_clear_double_bits (NODE_T * p)
1277 {
1278 A68G_LONG_BITS j; A68G_INT i;
1279 POP_OBJECT (p, &j, A68G_LONG_BITS);
1280 POP_OBJECT (p, &i, A68G_INT);
1281 int k = VALUE (&i);
1282 PRELUDE_ERROR (k < 1 || k > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1283 UNSIGNED_T mask = 0x1, *w;
1284 if (k <= A68G_BITS_WIDTH) {
1285 w = &(HW (VALUE (&j)));
1286 } else {
1287 w = &(LW (VALUE (&j)));
1288 k -= A68G_BITS_WIDTH;
1289 }
1290 for (int n = 0; n < A68G_BITS_WIDTH - k; n++) {
1291 mask = mask << 1;
1292 }
1293 (*w) &= ~mask;
1294 PUSH_OBJECT (p, j, A68G_LONG_BITS);
1295 }
1296
1297 //! @brief OP SHL = (LONG BITS, INT) LONG BITS
1298
1299 void genie_shl_double_bits (NODE_T * p)
1300 {
1301 A68G_LONG_BITS i; A68G_INT j;
1302 POP_OBJECT (p, &j, A68G_INT);
1303 POP_OBJECT (p, &i, A68G_LONG_BITS);
1304 DOUBLE_NUM_T *w = &VALUE (&i);
1305 int k = VALUE (&j);
1306 if (VALUE (&j) >= 0) {
1307 for (int n = 0; n < k; n++) {
1308 UNSIGNED_T carry = ((LW (*w) & D_SIGN) ? 0x1 : 0x0);
1309 PRELUDE_ERROR (MODCHK (p, M_LONG_BITS, HW (*w) & D_SIGN), p, ERROR_MATH, M_LONG_BITS);
1310 HW (*w) = (HW (*w) << 1) | carry;
1311 LW (*w) = (LW (*w) << 1);
1312 }
1313 } else {
1314 k = -k;
1315 for (int n = 0; n < k; n++) {
1316 UNSIGNED_T carry = ((HW (*w) & 0x1) ? D_SIGN : 0x0);
1317 HW (*w) = (HW (*w) >> 1);
1318 LW (*w) = (LW (*w) >> 1) | carry;
1319 }
1320 }
1321 PUSH_OBJECT (p, i, A68G_LONG_BITS);
1322 }
1323
1324 //! @brief OP SHR = (LONG BITS, INT) LONG BITS
1325
1326 void genie_shr_double_bits (NODE_T * p)
1327 {
1328 A68G_INT *j;
1329 POP_OPERAND_ADDRESS (p, j, A68G_INT);
1330 VALUE (j) = -VALUE (j);
1331 genie_shl_double_bits (p); // Conform RR
1332 }
1333
1334 //! @brief OP ROL = (LONG BITS, INT) LONG BITS
1335
1336 void genie_rol_double_bits (NODE_T * p)
1337 {
1338 A68G_LONG_BITS i; A68G_INT j;
1339 DOUBLE_NUM_T *w = &VALUE (&i);
1340 POP_OBJECT (p, &j, A68G_INT);
1341 POP_OBJECT (p, &i, A68G_LONG_BITS);
1342 int k = VALUE (&j);
1343 if (k >= 0) {
1344 for (int n = 0; n < k; n++) {
1345 UNSIGNED_T carry = ((HW (*w) & D_SIGN) ? 0x1 : 0x0);
1346 UNSIGNED_T carry_between = ((LW (*w) & D_SIGN) ? 0x1 : 0x0);
1347 HW (*w) = (HW (*w) << 1) | carry_between;
1348 LW (*w) = (LW (*w) << 1) | carry;
1349 }
1350 } else {
1351 k = -k;
1352 for (int n = 0; n < k; n++) {
1353 UNSIGNED_T carry = ((LW (*w) & 0x1) ? D_SIGN : 0x0);
1354 UNSIGNED_T carry_between = ((HW (*w) & 0x1) ? D_SIGN : 0x0);
1355 HW (*w) = (HW (*w) >> 1) | carry;
1356 LW (*w) = (LW (*w) >> 1) | carry_between;
1357 }
1358 }
1359 PUSH_OBJECT (p, i, A68G_LONG_BITS);
1360 }
1361
1362 //! @brief OP ROR = (LONG BITS, INT) LONG BITS
1363
1364 void genie_ror_double_bits (NODE_T * p)
1365 {
1366 A68G_INT *j;
1367 POP_OPERAND_ADDRESS (p, j, A68G_INT);
1368 VALUE (j) = -VALUE (j);
1369 genie_rol_double_bits (p); // Conform RR
1370 }
1371
1372 //! @brief OP BIN = (LONG INT) LONG BITS
1373
1374 void genie_bin_double_int (NODE_T * p)
1375 {
1376 A68G_LONG_INT i;
1377 POP_OBJECT (p, &i, A68G_LONG_INT);
1378 // RR does not convert negative numbers
1379 if (D_NEG (VALUE (&i))) {
1380 errno = EDOM;
1381 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, M_BITS);
1382 exit_genie (p, A68G_RUNTIME_ERROR);
1383 }
1384 PUSH_OBJECT (p, i, A68G_LONG_BITS);
1385 }
1386
1387 //! @brief OP +* = (LONG REAL, LONG REAL) LONG COMPLEX
1388
1389 void genie_i_double_compl (NODE_T * p)
1390 {
1391 (void) p;
1392 }
1393
1394 //! @brief OP SHORTEN = (LONG COMPLEX) COMPLEX
1395
1396 void genie_shorten_double_compl_to_complex (NODE_T * p)
1397 {
1398 A68G_LONG_REAL re, im;
1399 POP_OBJECT (p, &im, A68G_LONG_REAL);
1400 POP_OBJECT (p, &re, A68G_LONG_REAL);
1401 REAL_T w = VALUE (&re).f;
1402 PUSH_VALUE (p, w, A68G_REAL);
1403 w = VALUE (&im).f;
1404 PUSH_VALUE (p, w, A68G_REAL);
1405 }
1406
1407 //! @brief OP LENG = (LONG COMPLEX) LONG LONG COMPLEX
1408
1409 void genie_lengthen_double_compl_to_long_mp_complex (NODE_T * p)
1410 {
1411 int digs = DIGITS (M_LONG_LONG_REAL);
1412 A68G_LONG_REAL re, im;
1413 POP_OBJECT (p, &im, A68G_LONG_REAL);
1414 POP_OBJECT (p, &re, A68G_LONG_REAL);
1415 MP_T *z = nil_mp (p, digs);
1416 (void) double_to_mp (p, z, VALUE (&re).f, A68G_DOUBLE_DIG, A68G_FALSE, digs);
1417 MP_STATUS (z) = (MP_T) INIT_MASK;
1418 z = nil_mp (p, digs);
1419 (void) double_to_mp (p, z, VALUE (&im).f, A68G_DOUBLE_DIG, A68G_FALSE, digs);
1420 MP_STATUS (z) = (MP_T) INIT_MASK;
1421 }
1422
1423 //! @brief OP +* = (LONG INT, LONG INT) LONG COMPLEX
1424
1425 void genie_i_int_double_compl (NODE_T * p)
1426 {
1427 A68G_LONG_INT re, im;
1428 POP_OBJECT (p, &im, A68G_LONG_INT);
1429 POP_OBJECT (p, &re, A68G_LONG_INT);
1430 PUSH_VALUE (p, double_int_to_double (p, VALUE (&re)), A68G_LONG_REAL);
1431 PUSH_VALUE (p, double_int_to_double (p, VALUE (&im)), A68G_LONG_REAL);
1432 }
1433
1434 //! @brief OP RE = (LONG COMPLEX) LONG REAL
1435
1436 void genie_re_double_compl (NODE_T * p)
1437 {
1438 DECREMENT_STACK_POINTER (p, SIZE (M_LONG_REAL));
1439 }
1440
1441 //! @brief OP IM = (LONG COMPLEX) LONG REAL
1442
1443 void genie_im_double_compl (NODE_T * p)
1444 {
1445 A68G_LONG_REAL re, im;
1446 POP_OBJECT (p, &im, A68G_LONG_REAL);
1447 POP_OBJECT (p, &re, A68G_LONG_REAL);
1448 PUSH_OBJECT (p, im, A68G_LONG_REAL);
1449 }
1450
1451 //! @brief OP - = (LONG COMPLEX) LONG COMPLEX
1452
1453 void genie_minus_double_compl (NODE_T * p)
1454 {
1455 A68G_LONG_REAL re, im;
1456 POP_OBJECT (p, &im, A68G_LONG_REAL);
1457 POP_OBJECT (p, &re, A68G_LONG_REAL);
1458 VALUE (&re).f = -VALUE (&re).f;
1459 VALUE (&im).f = -VALUE (&im).f;
1460 PUSH_OBJECT (p, im, A68G_LONG_REAL);
1461 PUSH_OBJECT (p, re, A68G_LONG_REAL);
1462 }
1463
1464 //! @brief OP ABS = (LONG COMPLEX) LONG REAL
1465
1466 void genie_abs_double_compl (NODE_T * p)
1467 {
1468 A68G_LONG_REAL re, im;
1469 POP_LONG_COMPLEX (p, &re, &im);
1470 PUSH_VALUE (p, dble (a68g_hypot_double (VALUE (&re).f, VALUE (&im).f)), A68G_LONG_REAL);
1471 }
1472
1473 //! @brief OP ARG = (LONG COMPLEX) LONG REAL
1474
1475 void genie_arg_double_compl (NODE_T * p)
1476 {
1477 A68G_LONG_REAL re, im;
1478 POP_LONG_COMPLEX (p, &re, &im);
1479 PRELUDE_ERROR (VALUE (&re).f == 0.0q && VALUE (&im).f == 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_COMPLEX);
1480 PUSH_VALUE (p, dble (atan2_double (VALUE (&im).f, VALUE (&re).f)), A68G_LONG_REAL);
1481 }
1482
1483 //! @brief OP CONJ = (LONG COMPLEX) LONG COMPLEX
1484
1485 void genie_conj_double_compl (NODE_T * p)
1486 {
1487 A68G_LONG_REAL im;
1488 POP_OBJECT (p, &im, A68G_LONG_REAL);
1489 VALUE (&im).f = -VALUE (&im).f;
1490 PUSH_OBJECT (p, im, A68G_LONG_REAL);
1491 }
1492
1493 //! @brief OP + = (COMPLEX, COMPLEX) COMPLEX
1494
1495 void genie_add_double_compl (NODE_T * p)
1496 {
1497 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1498 POP_LONG_COMPLEX (p, &re_y, &im_y);
1499 POP_LONG_COMPLEX (p, &re_x, &im_x);
1500 VALUE (&re_x).f += VALUE (&re_y).f;
1501 VALUE (&im_x).f += VALUE (&im_y).f;
1502 CHECK_DOUBLE_COMPLEX (p, VALUE (&im_x).f, VALUE (&im_y).f);
1503 PUSH_OBJECT (p, re_x, A68G_LONG_REAL);
1504 PUSH_OBJECT (p, im_x, A68G_LONG_REAL);
1505 }
1506
1507 //! @brief OP - = (COMPLEX, COMPLEX) COMPLEX
1508
1509 void genie_sub_double_compl (NODE_T * p)
1510 {
1511 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1512 POP_LONG_COMPLEX (p, &re_y, &im_y);
1513 POP_LONG_COMPLEX (p, &re_x, &im_x);
1514 VALUE (&re_x).f -= VALUE (&re_y).f;
1515 VALUE (&im_x).f -= VALUE (&im_y).f;
1516 CHECK_DOUBLE_COMPLEX (p, VALUE (&im_x).f, VALUE (&im_y).f);
1517 PUSH_OBJECT (p, re_x, A68G_LONG_REAL);
1518 PUSH_OBJECT (p, im_x, A68G_LONG_REAL);
1519 }
1520
1521 //! @brief OP * = (COMPLEX, COMPLEX) COMPLEX
1522
1523 void genie_mul_double_compl (NODE_T * p)
1524 {
1525 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1526 POP_LONG_COMPLEX (p, &re_y, &im_y);
1527 POP_LONG_COMPLEX (p, &re_x, &im_x);
1528 DOUBLE_T re = VALUE (&re_x).f * VALUE (&re_y).f - VALUE (&im_x).f * VALUE (&im_y).f;
1529 DOUBLE_T im = VALUE (&im_x).f * VALUE (&re_y).f + VALUE (&re_x).f * VALUE (&im_y).f;
1530 CHECK_DOUBLE_COMPLEX (p, VALUE (&im_x).f, VALUE (&im_y).f);
1531 PUSH_VALUE (p, dble (re), A68G_LONG_REAL);
1532 PUSH_VALUE (p, dble (im), A68G_LONG_REAL);
1533 }
1534
1535 //! @brief OP / = (COMPLEX, COMPLEX) COMPLEX
1536
1537 void genie_div_double_compl (NODE_T * p)
1538 {
1539 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1540 DOUBLE_T re = 0.0, im = 0.0;
1541 POP_LONG_COMPLEX (p, &re_y, &im_y);
1542 POP_LONG_COMPLEX (p, &re_x, &im_x);
1543 PRELUDE_ERROR (VALUE (&re_y).f == 0.0q && VALUE (&im_y).f == 0.0q, p, ERROR_DIVISION_BY_ZERO, M_LONG_COMPLEX);
1544 if (ABSQ (VALUE (&re_y).f) >= ABSQ (VALUE (&im_y).f)) {
1545 DOUBLE_T r = VALUE (&im_y).f / VALUE (&re_y).f, den = VALUE (&re_y).f + r * VALUE (&im_y).f;
1546 re = (VALUE (&re_x).f + r * VALUE (&im_x).f) / den;
1547 im = (VALUE (&im_x).f - r * VALUE (&re_x).f) / den;
1548 } else {
1549 DOUBLE_T r = VALUE (&re_y).f / VALUE (&im_y).f, den = VALUE (&im_y).f + r * VALUE (&re_y).f;
1550 re = (VALUE (&re_x).f * r + VALUE (&im_x).f) / den;
1551 im = (VALUE (&im_x).f * r - VALUE (&re_x).f) / den;
1552 }
1553 PUSH_VALUE (p, dble (re), A68G_LONG_REAL);
1554 PUSH_VALUE (p, dble (im), A68G_LONG_REAL);
1555 }
1556
1557 //! @brief OP ** = (LONG COMPLEX, INT) LONG COMPLEX
1558
1559 void genie_pow_double_compl_int (NODE_T * p)
1560 {
1561 A68G_LONG_REAL re_x, im_x;
1562 A68G_INT j;
1563 BOOL_T negative;
1564 POP_OBJECT (p, &j, A68G_INT);
1565 POP_LONG_COMPLEX (p, &re_x, &im_x);
1566 DOUBLE_T re_z = 1.0q, im_z = 0.0q;
1567 DOUBLE_T re_y = VALUE (&re_x).f, im_y = VALUE (&im_x).f;
1568 negative = (BOOL_T) (VALUE (&j) < 0);
1569 if (negative) {
1570 VALUE (&j) = -VALUE (&j);
1571 }
1572 INT_T expo = 1;
1573 while ((UNSIGNED_T) expo <= (UNSIGNED_T) (VALUE (&j))) {
1574 DOUBLE_T z;
1575 if (expo & VALUE (&j)) {
1576 z = re_z * re_y - im_z * im_y;
1577 im_z = re_z * im_y + im_z * re_y;
1578 re_z = z;
1579 }
1580 z = re_y * re_y - im_y * im_y;
1581 im_y = im_y * re_y + re_y * im_y;
1582 re_y = z;
1583 CHECK_DOUBLE_COMPLEX (p, re_y, im_y);
1584 CHECK_DOUBLE_COMPLEX (p, re_z, im_z);
1585 expo <<= 1;
1586 }
1587 if (negative) {
1588 PUSH_VALUE (p, dble (1.0q), A68G_LONG_REAL);
1589 PUSH_VALUE (p, dble (0.0q), A68G_LONG_REAL);
1590 PUSH_VALUE (p, dble (re_z), A68G_LONG_REAL);
1591 PUSH_VALUE (p, dble (im_z), A68G_LONG_REAL);
1592 genie_div_double_compl (p);
1593 } else {
1594 PUSH_VALUE (p, dble (re_z), A68G_LONG_REAL);
1595 PUSH_VALUE (p, dble (im_z), A68G_LONG_REAL);
1596 }
1597 }
1598
1599 //! @brief OP = = (COMPLEX, COMPLEX) BOOL
1600
1601 void genie_eq_double_compl (NODE_T * p)
1602 {
1603 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1604 POP_LONG_COMPLEX (p, &re_y, &im_y);
1605 POP_LONG_COMPLEX (p, &re_x, &im_x);
1606 PUSH_VALUE (p, (BOOL_T) ((VALUE (&re_x).f == VALUE (&re_y).f) && (VALUE (&im_x).f == VALUE (&im_y).f)), A68G_BOOL);
1607 }
1608
1609 //! @brief OP /= = (COMPLEX, COMPLEX) BOOL
1610
1611 void genie_ne_double_compl (NODE_T * p)
1612 {
1613 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1614 POP_LONG_COMPLEX (p, &re_y, &im_y);
1615 POP_LONG_COMPLEX (p, &re_x, &im_x);
1616 PUSH_VALUE (p, (BOOL_T) ! ((VALUE (&re_x).f == VALUE (&re_y).f) && (VALUE (&im_x).f == VALUE (&im_y).f)), A68G_BOOL);
1617 }
1618
1619 //! @brief OP +:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1620
1621 void genie_plusab_double_compl (NODE_T * p)
1622 {
1623 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_add_double_compl);
1624 }
1625
1626 //! @brief OP -:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1627
1628 void genie_minusab_double_compl (NODE_T * p)
1629 {
1630 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_sub_double_compl);
1631 }
1632
1633 //! @brief OP *:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1634
1635 void genie_timesab_double_compl (NODE_T * p)
1636 {
1637 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_mul_double_compl);
1638 }
1639
1640 //! @brief OP /:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1641
1642 void genie_divab_double_compl (NODE_T * p)
1643 {
1644 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_div_double_compl);
1645 }
1646
1647 //! @brief OP LENG = (COMPLEX) LONG COMPLEX
1648
1649 void genie_lengthen_complex_to_double_compl (NODE_T * p)
1650 {
1651 A68G_REAL i;
1652 POP_OBJECT (p, &i, A68G_REAL);
1653 genie_lengthen_real_to_double (p);
1654 PUSH_OBJECT (p, i, A68G_REAL);
1655 genie_lengthen_real_to_double (p);
1656 }
1657
1658 // Functions
1659
1660 //! @brief OP ROUND = (LONG REAL) LONG INT
1661
1662 void genie_round_double (NODE_T * p)
1663 {
1664 A68G_LONG_REAL x;
1665 POP_OBJECT (p, &x, A68G_LONG_REAL);
1666 DOUBLE_NUM_T u = VALUE (&x);
1667 if (u.f < 0.0q) {
1668 u.f = u.f - 0.5q;
1669 } else {
1670 u.f = u.f + 0.5q;
1671 }
1672 PUSH_VALUE (p, double_to_double_int (p, u), A68G_LONG_INT);
1673 }
1674
1675 //! @brief OP ENTIER = (LONG REAL) LONG INT
1676
1677 void genie_entier_double (NODE_T * p)
1678 {
1679 A68G_LONG_REAL x;
1680 POP_OBJECT (p, &x, A68G_LONG_REAL);
1681 DOUBLE_NUM_T u = VALUE (&x);
1682 u.f = floor_double (u.f);
1683 PUSH_VALUE (p, double_to_double_int (p, u), A68G_LONG_INT);
1684 }
1685
1686 //! @brief OP CEIL = (LONG REAL) LONG INT
1687
1688 void genie_ceil_double (NODE_T * p)
1689 {
1690 A68G_LONG_REAL x;
1691 POP_OBJECT (p, &x, A68G_LONG_REAL);
1692 DOUBLE_NUM_T u = VALUE (&x);
1693 u.f = ceil_double (u.f);
1694 PUSH_VALUE (p, double_to_double_int (p, u), A68G_LONG_INT);
1695 }
1696
1697 //! @brief OP TRUNC = (LONG REAL) LONG INT
1698
1699 void genie_trunc_double (NODE_T * p)
1700 {
1701 A68G_LONG_REAL x;
1702 POP_OBJECT (p, &x, A68G_LONG_REAL);
1703 DOUBLE_NUM_T u = VALUE (&x);
1704 PUSH_VALUE (p, double_to_double_int (p, u), A68G_LONG_INT);
1705 }
1706
1707 //! @brief OP FRAC = (LONG REAL) LONG REAL
1708
1709 void genie_frac_double (NODE_T * p)
1710 {
1711 A68G_LONG_REAL x;
1712 POP_OBJECT (p, &x, A68G_LONG_REAL);
1713 DOUBLE_NUM_T u = VALUE (&x), v, w;
1714 v.f = fabs_double (u.f);
1715 w.f = v.f - floor_double (v.f);
1716 if (u.f < 0.0q) {
1717 w.f = -w.f;
1718 }
1719 PUSH_VALUE (p, w, A68G_LONG_REAL);
1720 }
1721
1722 #define CD_FUNCTION(name, fun)\
1723 void name (NODE_T * p) {\
1724 A68G_LONG_REAL *x;\
1725 POP_OPERAND_ADDRESS (p, x, A68G_LONG_REAL);\
1726 errno = 0;\
1727 VALUE (x).f = fun (VALUE (x).f);\
1728 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);\
1729 }
1730
1731 CD_FUNCTION (genie_acos_double, acos_double);
1732 CD_FUNCTION (genie_acosh_double, acosh_double);
1733 CD_FUNCTION (genie_asinh_double, asinh_double);
1734 CD_FUNCTION (genie_atanh_double, atanh_double);
1735 CD_FUNCTION (genie_asin_double, asin_double);
1736 CD_FUNCTION (genie_atan_double, atan_double);
1737 CD_FUNCTION (genie_cosh_double, cosh_double);
1738 CD_FUNCTION (genie_cos_double, cos_double);
1739 CD_FUNCTION (genie_curt_double, cbrt_double);
1740 CD_FUNCTION (genie_exp_double, exp_double);
1741 CD_FUNCTION (genie_ln_double, log_double);
1742 CD_FUNCTION (genie_log_double, log10_double);
1743 CD_FUNCTION (genie_sinh_double, sinh_double);
1744 CD_FUNCTION (genie_sin_double, sin_double);
1745 CD_FUNCTION (genie_sqrt_double, sqrt_double);
1746 CD_FUNCTION (genie_tanh_double, tanh_double);
1747 CD_FUNCTION (genie_tan_double, tan_double);
1748 CD_FUNCTION (genie_erf_double, erf_double);
1749 CD_FUNCTION (genie_erfc_double, erfc_double);
1750 CD_FUNCTION (genie_lngamma_double, lgamma_double);
1751 CD_FUNCTION (genie_gamma_double, tgamma_double);
1752 CD_FUNCTION (genie_csc_double, a68g_csc_double);
1753 CD_FUNCTION (genie_cscdg_double, a68g_cscdg_double);
1754 CD_FUNCTION (genie_acsc_double, a68g_acsc_double);
1755 CD_FUNCTION (genie_acscdg_double, a68g_acscdg_double);
1756 CD_FUNCTION (genie_sec_double, a68g_sec_double);
1757 CD_FUNCTION (genie_secdg_double, a68g_secdg_double);
1758 CD_FUNCTION (genie_asec_double, a68g_asec_double);
1759 CD_FUNCTION (genie_asecdg_double, a68g_asecdg_double);
1760 CD_FUNCTION (genie_cot_double, a68g_cot_double);
1761 CD_FUNCTION (genie_acot_double, a68g_acot_double);
1762 CD_FUNCTION (genie_sindg_double, a68g_sindg_double);
1763 CD_FUNCTION (genie_cas_double, a68g_cas_double);
1764 CD_FUNCTION (genie_cosdg_double, a68g_cosdg_double);
1765 CD_FUNCTION (genie_tandg_double, a68g_tandg_double);
1766 CD_FUNCTION (genie_asindg_double, a68g_asindg_double);
1767 CD_FUNCTION (genie_acosdg_double, a68g_acosdg_double);
1768 CD_FUNCTION (genie_atandg_double, a68g_atandg_double);
1769 CD_FUNCTION (genie_cotdg_double, a68g_cotdg_double);
1770 CD_FUNCTION (genie_acotdg_double, a68g_acotdg_double);
1771 CD_FUNCTION (genie_sinpi_double, a68g_sinpi_double);
1772 CD_FUNCTION (genie_cospi_double, a68g_cospi_double);
1773 CD_FUNCTION (genie_tanpi_double, a68g_tanpi_double);
1774 CD_FUNCTION (genie_cotpi_double, a68g_cotpi_double);
1775
1776 //! @brief PROC long arctan2 = (LONG REAL) LONG REAL
1777
1778 void genie_atan2_double (NODE_T * p)
1779 {
1780 A68G_LONG_REAL x, y;
1781 POP_OBJECT (p, &y, A68G_LONG_REAL);
1782 POP_OBJECT (p, &x, A68G_LONG_REAL);
1783 errno = 0;
1784 PRELUDE_ERROR (VALUE (&x).f == 0.0q && VALUE (&y).f == 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
1785 VALUE (&x).f = a68g_atan2_real (VALUE (&y).f, VALUE (&x).f);
1786 PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
1787 PUSH_OBJECT (p, x, A68G_LONG_REAL);
1788 }
1789
1790 //! @brief PROC long arctan2dg = (LONG REAL) LONG REAL
1791
1792 void genie_atan2dg_double (NODE_T * p)
1793 {
1794 A68G_LONG_REAL x, y;
1795 POP_OBJECT (p, &y, A68G_LONG_REAL);
1796 POP_OBJECT (p, &x, A68G_LONG_REAL);
1797 errno = 0;
1798 PRELUDE_ERROR (VALUE (&x).f == 0.0q && VALUE (&y).f == 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
1799 VALUE (&x).f = CONST_180_OVER_PI_Q * a68g_atan2_real (VALUE (&y).f, VALUE (&x).f);
1800 PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
1801 PUSH_OBJECT (p, x, A68G_LONG_REAL);
1802 }
1803
1804 //! @brief PROC (LONG REAL) LONG REAL inverf
1805
1806 void genie_inverf_double (NODE_T * _p_)
1807 {
1808 A68G_LONG_REAL x;
1809 DOUBLE_T y, z;
1810 POP_OBJECT (_p_, &x, A68G_LONG_REAL);
1811 errno = 0;
1812 y = VALUE (&x).f;
1813 z = inverf_double (y);
1814 MATH_RTE (_p_, errno != 0, M_LONG_REAL, NO_TEXT);
1815 CHECK_DOUBLE_REAL (_p_, z);
1816 PUSH_VALUE (_p_, dble (z), A68G_LONG_REAL);
1817 }
1818
1819 //! @brief PROC (LONG REAL) LONG REAL inverfc
1820
1821 void genie_inverfc_double (NODE_T * p)
1822 {
1823 A68G_LONG_REAL *u;
1824 POP_OPERAND_ADDRESS (p, u, A68G_LONG_REAL);
1825 VALUE (u).f = 1.0q - (VALUE (u).f);
1826 genie_inverf_double (p);
1827 }
1828
1829 #define CD_C_FUNCTION(p, g)\
1830 A68G_LONG_REAL re, im;\
1831 DOUBLE_COMPLEX_T z;\
1832 POP_OBJECT (p, &im, A68G_LONG_REAL);\
1833 POP_OBJECT (p, &re, A68G_LONG_REAL);\
1834 errno = 0;\
1835 z = VALUE (&re).f + VALUE (&im).f * _Complex_I;\
1836 z = g (z);\
1837 PUSH_VALUE (p, dble ((DOUBLE_T) creal_double (z)), A68G_LONG_REAL);\
1838 PUSH_VALUE (p, dble ((DOUBLE_T) cimag_double (z)), A68G_LONG_REAL);\
1839 MATH_RTE (p, errno != 0, M_COMPLEX, NO_TEXT);
1840
1841 //! @brief PROC long csqrt = (LONG COMPLEX) LONG COMPLEX
1842
1843 void genie_sqrt_double_compl (NODE_T * p)
1844 {
1845 CD_C_FUNCTION (p, csqrt_double);
1846 }
1847
1848 //! @brief PROC long csin = (LONG COMPLEX) LONG COMPLEX
1849
1850 void genie_sin_double_compl (NODE_T * p)
1851 {
1852 CD_C_FUNCTION (p, csin_double);
1853 }
1854
1855 //! @brief PROC long ccos = (LONG COMPLEX) LONG COMPLEX
1856
1857 void genie_cos_double_compl (NODE_T * p)
1858 {
1859 CD_C_FUNCTION (p, ccos_double);
1860 }
1861
1862 //! @brief PROC long ctan = (LONG COMPLEX) LONG COMPLEX
1863
1864 void genie_tan_double_compl (NODE_T * p)
1865 {
1866 CD_C_FUNCTION (p, ctan_double);
1867 }
1868
1869 //! @brief PROC long casin = (LONG COMPLEX) LONG COMPLEX
1870
1871 void genie_asin_double_compl (NODE_T * p)
1872 {
1873 CD_C_FUNCTION (p, casin_double);
1874 }
1875
1876 //! @brief PROC long cacos = (LONG COMPLEX) LONG COMPLEX
1877
1878 void genie_acos_double_compl (NODE_T * p)
1879 {
1880 CD_C_FUNCTION (p, cacos_double);
1881 }
1882
1883 //! @brief PROC long catan = (LONG COMPLEX) LONG COMPLEX
1884
1885 void genie_atan_double_compl (NODE_T * p)
1886 {
1887 CD_C_FUNCTION (p, catan_double);
1888 }
1889
1890 //! @brief PROC long cexp = (LONG COMPLEX) LONG COMPLEX
1891
1892 void genie_exp_double_compl (NODE_T * p)
1893 {
1894 CD_C_FUNCTION (p, cexp_double);
1895 }
1896
1897 //! @brief PROC long cln = (LONG COMPLEX) LONG COMPLEX
1898
1899 void genie_ln_double_compl (NODE_T * p)
1900 {
1901 CD_C_FUNCTION (p, clog_double);
1902 }
1903
1904 //! @brief PROC long csinh = (LONG COMPLEX) LONG COMPLEX
1905
1906 void genie_sinh_double_compl (NODE_T * p)
1907 {
1908 CD_C_FUNCTION (p, csinh_double);
1909 }
1910
1911 //! @brief PROC long ccosh = (LONG COMPLEX) LONG COMPLEX
1912
1913 void genie_cosh_double_compl (NODE_T * p)
1914 {
1915 CD_C_FUNCTION (p, ccosh_double);
1916 }
1917
1918 //! @brief PROC long ctanh = (LONG COMPLEX) LONG COMPLEX
1919
1920 void genie_tanh_double_compl (NODE_T * p)
1921 {
1922 CD_C_FUNCTION (p, ctanh_double);
1923 }
1924
1925 //! @brief PROC long casinh = (LONG COMPLEX) LONG COMPLEX
1926
1927 void genie_asinh_double_compl (NODE_T * p)
1928 {
1929 CD_C_FUNCTION (p, casinh_double);
1930 }
1931
1932 //! @brief PROC long cacosh = (LONG COMPLEX) LONG COMPLEX
1933
1934 void genie_acosh_double_compl (NODE_T * p)
1935 {
1936 CD_C_FUNCTION (p, cacosh_double);
1937 }
1938
1939 //! @brief PROC long catanh = (LONG COMPLEX) LONG COMPLEX
1940
1941 void genie_atanh_double_compl (NODE_T * p)
1942 {
1943 CD_C_FUNCTION (p, catanh_double);
1944 }
1945
1946 //! @brief PROC next long random = LONG REAL
1947
1948 void genie_next_random_double (NODE_T * p)
1949 {
1950 // This is 'real width' digits only.
1951 genie_next_random (p);
1952 genie_lengthen_real_to_double (p);
1953 }
1954
1955 #define CALL(g, x, y) {\
1956 ADDR_T pop_sp = A68G_SP;\
1957 A68G_LONG_REAL *z = (A68G_LONG_REAL *) STACK_TOP;\
1958 DOUBLE_NUM_T _w_;\
1959 _w_.f = (x);\
1960 PUSH_VALUE (_p_, _w_, A68G_LONG_REAL);\
1961 genie_call_procedure (_p_, M_PROC_LONG_REAL_LONG_REAL, M_PROC_LONG_REAL_LONG_REAL, M_PROC_LONG_REAL_LONG_REAL, &(g), pop_sp, pop_fp);\
1962 (y) = VALUE (z).f;\
1963 A68G_SP = pop_sp;\
1964 }
1965
1966 //! @brief Transform string into real-16.
1967
1968 DOUBLE_T string_to_double (char *s, char **end)
1969 {
1970 errno = 0;
1971 DOUBLE_T y[A68G_DOUBLE_DIG];
1972 for (int i = 0; i < A68G_DOUBLE_DIG; i++) {
1973 y[i] = 0.0q;
1974 }
1975 if (end != NO_REF) {
1976 (*end) = &(s[0]);
1977 }
1978 while (IS_SPACE (s[0])) {
1979 s++;
1980 }
1981 // Scan mantissa digits and put them into "y".
1982 DOUBLE_T W;
1983 if (s[0] == '-') {
1984 W = -1.0q;
1985 } else {
1986 W = 1.0q;
1987 }
1988 if (s[0] == '+' || s[0] == '-') {
1989 s++;
1990 }
1991 while (s[0] == '0') {
1992 s++;
1993 }
1994 int dot = -1, pos = 0, pow = 0;
1995 while (pow < A68G_DOUBLE_DIG && s[pos] != NULL_CHAR && (IS_DIGIT (s[pos]) || s[pos] == POINT_CHAR)) {
1996 if (s[pos] == POINT_CHAR) {
1997 dot = pos;
1998 } else {
1999 int val = (int) s[pos] - (int) '0';
2000 y[pow] = W * val;
2001 W /= 10.0q;
2002 pow++;
2003 }
2004 pos++;
2005 }
2006 while (IS_DIGIT (s[pos])) {
2007 pos++;
2008 }
2009 if (end != NO_REF) {
2010 (*end) = &(s[pos]);
2011 }
2012 // Sum from low to high to preserve precision.
2013 DOUBLE_T sum = 0.0q;
2014 for (int i = A68G_DOUBLE_DIG - 1; i >= 0; i--) {
2015 sum = sum + y[i];
2016 }
2017 // See if there is an exponent.
2018 int expo;
2019 if (s[pos] != NULL_CHAR && TO_UPPER (s[pos]) == TO_UPPER (EXPONENT_CHAR)) {
2020 expo = (int) strtol (&(s[++pos]), end, 10);
2021 } else {
2022 expo = 0;
2023 }
2024 // Standardise.
2025 if (dot >= 0) {
2026 expo += dot - 1;
2027 } else {
2028 expo += pow - 1;
2029 }
2030 while (sum != 0.0q && fabs_double (sum) < 1.0q) {
2031 sum *= 10.0q;
2032 expo -= 1;
2033 }
2034 if (errno == 0) {
2035 return sum * ten_up_double (expo);
2036 } else {
2037 return 0.0q;
2038 }
2039 }
2040
2041 void genie_beta_inc_cf_double (NODE_T * p)
2042 {
2043 A68G_LONG_REAL x, s, t;
2044 POP_OBJECT (p, &x, A68G_LONG_REAL);
2045 POP_OBJECT (p, &t, A68G_LONG_REAL);
2046 POP_OBJECT (p, &s, A68G_LONG_REAL);
2047 errno = 0;
2048 PUSH_VALUE (p, dble (a68g_beta_inc_double (VALUE (&s).f, VALUE (&t).f, VALUE (&x).f)), A68G_LONG_REAL);
2049 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
2050 }
2051
2052 void genie_beta_double (NODE_T * p)
2053 {
2054 A68G_LONG_REAL a, b;
2055 POP_OBJECT (p, &b, A68G_LONG_REAL);
2056 POP_OBJECT (p, &a, A68G_LONG_REAL);
2057 errno = 0;
2058 PUSH_VALUE (p, dble (exp_double (lgamma_double (VALUE (&a).f) + lgamma_double (VALUE (&b).f) - lgamma_double (VALUE (&a).f + VALUE (&b).f))), A68G_LONG_REAL);
2059 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
2060 }
2061
2062 void genie_ln_beta_double (NODE_T * p)
2063 {
2064 A68G_LONG_REAL a, b;
2065 POP_OBJECT (p, &b, A68G_LONG_REAL);
2066 POP_OBJECT (p, &a, A68G_LONG_REAL);
2067 errno = 0;
2068 PUSH_VALUE (p, dble (lgamma_double (VALUE (&a).f) + lgamma_double (VALUE (&b).f) - lgamma_double (VALUE (&a).f + VALUE (&b).f)), A68G_LONG_REAL);
2069 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
2070 }
2071
2072 // LONG REAL infinity
2073
2074 void genie_infinity_double (NODE_T * p)
2075 {
2076 PUSH_VALUE (p, dble (A68G_POSINF_DOUBLE), A68G_LONG_REAL);
2077 }
2078
2079 // LONG REAL minus infinity
2080
2081 void genie_minus_infinity_double (NODE_T * p)
2082 {
2083 PUSH_VALUE (p, dble (A68G_MININF_DOUBLE), A68G_LONG_REAL);
2084 }
2085
2086 // Range check.
2087
2088 BOOL_T a68g_finite_double (DOUBLE_T x)
2089 {
2090 if (a68g_isinf_double (x)) {
2091 return A68G_FALSE;
2092 } else if (a68g_isnan_double (x)) {
2093 return A68G_FALSE;
2094 } else {
2095 return A68G_TRUE;
2096 }
2097 }
2098
2099 // Range check.
2100
2101 BOOL_T a68g_isnan_double (DOUBLE_T x)
2102 {
2103 return isnanq (x);
2104 }
2105
2106 // Range check.
2107
2108 BOOL_T a68g_isinf_double (DOUBLE_T x)
2109 {
2110 if (x == a68g_posinf_double()) {
2111 return A68G_TRUE;
2112 } else if (x == a68g_mininf_double()) {
2113 return A68G_TRUE;
2114 } else {
2115 return A68G_FALSE;
2116 }
2117 }
2118
2119 #endif
© J.M. van der Veer • jmvdveer@algol68genie.nl