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@xs4all.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 MP_STATUS (z) = (MP_T) INIT_MASK;
495 }
496
497 //! @brief OP SHORTEN = (LONG LONG REAL) LONG REAL
498
499 void genie_shorten_mp_to_double (NODE_T * p)
500 {
501 MOID_T *mode = LHS_MODE (p);
502 int digs = DIGITS (mode), size = SIZE (mode);
503 DOUBLE_NUM_T d;
504 DECREMENT_STACK_POINTER (p, size);
505 MP_T *z = (MP_T *) STACK_TOP;
506 MP_STATUS (z) = (MP_T) INIT_MASK;
507 d.f = mp_to_double (p, z, digs);
508 PUSH_VALUE (p, d, A68G_LONG_REAL);
509 }
510
511 //! @brief OP SHORTEN = (LONG LONG COMPLEX) LONG COMPLEX
512
513 void genie_shorten_long_mp_complex_to_double_compl (NODE_T * p)
514 {
515 int digs = DIGITS (M_LONG_LONG_REAL), size = SIZE (M_LONG_LONG_REAL);
516 MP_T *b = (MP_T *) STACK_OFFSET (-size);
517 MP_T *a = (MP_T *) STACK_OFFSET (-2 * size);
518 DECREMENT_STACK_POINTER (p, 2 * size);
519 DOUBLE_NUM_T u, v;
520 u.f = mp_to_double (p, a, digs);
521 v.f = mp_to_double (p, b, digs);
522 PUSH_VALUE (p, u, A68G_LONG_REAL);
523 PUSH_VALUE (p, v, A68G_LONG_REAL);
524 }
525
526 //! @brief OP LENG = (LONG INT) LONG LONG INT
527
528 void genie_lengthen_double_int_to_mp (NODE_T * p)
529 {
530 int digs = DIGITS (M_LONG_LONG_INT);
531 A68G_LONG_INT k;
532 POP_OBJECT (p, &k, A68G_LONG_INT);
533 MP_T *z = nil_mp (p, digs);
534 (void) double_int_to_mp (p, z, VALUE (&k), digs);
535 MP_STATUS (z) = (MP_T) INIT_MASK;
536 }
537
538 //! @brief OP SHORTEN = (LONG LONG INT) LONG INT
539
540 void genie_shorten_mp_to_double_int (NODE_T * p)
541 {
542 MOID_T *mode = LHS_MODE (p);
543 int digs = DIGITS (mode), size = SIZE (mode);
544 DECREMENT_STACK_POINTER (p, size);
545 MP_T *z = (MP_T *) STACK_TOP;
546 MP_STATUS (z) = (MP_T) INIT_MASK;
547 PUSH_VALUE (p, mp_to_double_int (p, z, digs), A68G_LONG_INT);
548 }
549
550 //! @brief OP LENG = (INT) LONG INT
551
552 void genie_lengthen_int_to_double_int (NODE_T * p)
553 {
554 A68G_INT k;
555 POP_OBJECT (p, &k, A68G_INT);
556 INT_T v = VALUE (&k);
557 DOUBLE_NUM_T d;
558 if (v >= 0) {
559 LW (d) = v;
560 HW (d) = 0;
561 } else {
562 LW (d) = -v;
563 HW (d) = D_SIGN;
564 }
565 PUSH_VALUE (p, d, A68G_LONG_INT);
566 }
567
568 //! @brief OP SHORTEN = (LONG INT) INT
569
570 void genie_shorten_long_int_to_int (NODE_T * p)
571 {
572 A68G_LONG_INT k;
573 POP_OBJECT (p, &k, A68G_LONG_INT);
574 DOUBLE_NUM_T j = VALUE (&k);
575 PRELUDE_ERROR (HW (j) != 0 && HW (j) != D_SIGN, p, ERROR_MATH, M_INT);
576 PRELUDE_ERROR (LW (j) & D_SIGN, p, ERROR_MATH, M_INT);
577 if (D_NEG (j)) {
578 PUSH_VALUE (p, -LW (j), A68G_INT);
579 } else {
580 PUSH_VALUE (p, LW (j), A68G_INT);
581 }
582 }
583
584 // Constants.
585
586 //! @brief PROC long max int = LONG INT
587
588 void genie_double_max_int (NODE_T * p)
589 {
590 DOUBLE_NUM_T d;
591 HW (d) = 0x7fffffffffffffffLL;
592 LW (d) = 0xffffffffffffffffLL;
593 PUSH_VALUE (p, d, A68G_LONG_INT);
594 }
595
596 //! @brief PROC long max bits = LONG BITS
597
598 void genie_double_max_bits (NODE_T * p)
599 {
600 DOUBLE_NUM_T d;
601 HW (d) = 0xffffffffffffffffLL;
602 LW (d) = 0xffffffffffffffffLL;
603 PUSH_VALUE (p, d, A68G_LONG_INT);
604 }
605
606 //! @brief LONG REAL max long real
607
608 void genie_double_max_real (NODE_T * p)
609 {
610 DOUBLE_NUM_T d;
611 d.f = A68G_DOUBLE_MAX;
612 PUSH_VALUE (p, d, A68G_LONG_REAL);
613 }
614
615 //! @brief LONG REAL min long real
616
617 void genie_double_min_real (NODE_T * p)
618 {
619 DOUBLE_NUM_T d;
620 d.f = A68G_DOUBLE_MIN;
621 PUSH_VALUE (p, d, A68G_LONG_REAL);
622 }
623
624 //! @brief LONG REAL small long real
625
626 void genie_double_small_real (NODE_T * p)
627 {
628 DOUBLE_NUM_T d;
629 d.f = A68G_DOUBLE_EPS;
630 PUSH_VALUE (p, d, A68G_LONG_REAL);
631 }
632
633 //! @brief PROC long pi = LON REAL
634
635 void genie_pi_double (NODE_T * p)
636 {
637 DOUBLE_NUM_T w;
638 w.f = M_PIq;
639 PUSH_VALUE (p, w, A68G_LONG_INT);
640 }
641
642 // MONADs and DYADs
643
644 //! @brief OP SIGN = (LONG INT) INT
645
646 void genie_sign_double_int (NODE_T * p)
647 {
648 A68G_LONG_INT k;
649 POP_OBJECT (p, &k, A68G_LONG_INT);
650 PUSH_VALUE (p, sign_double_int (VALUE (&k)), A68G_INT);
651 }
652
653 //! @brief OP ABS = (LONG INT) LONG INT
654
655 void genie_abs_double_int (NODE_T * p)
656 {
657 A68G_LONG_INT *k;
658 POP_OPERAND_ADDRESS (p, k, A68G_LONG_INT);
659 VALUE (k) = abs_double_int (VALUE (k));
660 }
661
662 //! @brief OP ODD = (LONG INT) BOOL
663
664 void genie_odd_double_int (NODE_T * p)
665 {
666 A68G_LONG_INT j;
667 POP_OBJECT (p, &j, A68G_LONG_INT);
668 DOUBLE_NUM_T w = abs_double_int (VALUE (&j));
669 if (LW (w) & 0x1) {
670 PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
671 } else {
672 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
673 }
674 }
675
676 //! @brief OP - = (LONG INT) LONG INT
677
678 void genie_minus_double_int (NODE_T * p)
679 {
680 A68G_LONG_INT *k;
681 POP_OPERAND_ADDRESS (p, k, A68G_LONG_INT);
682 VALUE (k) = neg_double_int (VALUE (k));
683 }
684
685 //! @brief OP ROUND = (LONG REAL) LONG INT
686
687 void genie_round_double (NODE_T * p)
688 {
689 A68G_LONG_REAL x;
690 POP_OBJECT (p, &x, A68G_LONG_REAL);
691 DOUBLE_NUM_T u = VALUE (&x);
692 if (u.f < 0.0q) {
693 u.f = u.f - 0.5q;
694 } else {
695 u.f = u.f + 0.5q;
696 }
697 PUSH_VALUE (p, double_to_double_int (p, u), A68G_LONG_INT);
698 }
699
700 //! @brief OP ENTIER = (LONG REAL) LONG INT
701
702 void genie_entier_double (NODE_T * p)
703 {
704 A68G_LONG_REAL x;
705 POP_OBJECT (p, &x, A68G_LONG_REAL);
706 DOUBLE_NUM_T u = VALUE (&x);
707 u.f = floor_double (u.f);
708 PUSH_VALUE (p, double_to_double_int (p, u), A68G_LONG_INT);
709 }
710
711 //! @brief OP + = (LONG INT, LONG INT) LONG INT
712
713 void genie_add_double_int (NODE_T * p)
714 {
715 A68G_LONG_INT i, j;
716 POP_OBJECT (p, &j, A68G_LONG_INT);
717 POP_OBJECT (p, &i, A68G_LONG_INT);
718 PUSH_VALUE (p, double_sadd (p, VALUE (&i), VALUE (&j)), A68G_LONG_INT);
719 }
720
721 //! @brief OP - = (LONG INT, LONG INT) LONG INT
722
723 void genie_sub_double_int (NODE_T * p)
724 {
725 A68G_LONG_INT i, j;
726 POP_OBJECT (p, &j, A68G_LONG_INT);
727 POP_OBJECT (p, &i, A68G_LONG_INT);
728 PUSH_VALUE (p, double_ssub (p, VALUE (&i), VALUE (&j)), A68G_LONG_INT);
729 }
730
731 //! @brief OP * = (LONG INT, LONG INT) LONG INT
732
733 void genie_mul_double_int (NODE_T * p)
734 {
735 A68G_LONG_INT i, j;
736 POP_OBJECT (p, &j, A68G_LONG_INT);
737 POP_OBJECT (p, &i, A68G_LONG_INT);
738 PUSH_VALUE (p, double_smul (p, VALUE (&i), VALUE (&j)), A68G_LONG_INT);
739 }
740
741 //! @brief OP / = (LONG INT, LONG INT) LONG INT
742
743 void genie_over_double_int (NODE_T * p)
744 {
745 A68G_LONG_INT i, j;
746 POP_OBJECT (p, &j, A68G_LONG_INT);
747 POP_OBJECT (p, &i, A68G_LONG_INT);
748 PRELUDE_ERROR (D_ZERO (VALUE (&j)), p, ERROR_DIVISION_BY_ZERO, M_LONG_INT);
749 PUSH_VALUE (p, double_sdiv (p, VALUE (&i), VALUE (&j), 0), A68G_LONG_INT);
750 }
751
752 //! @brief OP MOD = (LONG INT, LONG INT) LONG INT
753
754 void genie_mod_double_int (NODE_T * p)
755 {
756 A68G_LONG_INT i, j;
757 POP_OBJECT (p, &j, A68G_LONG_INT);
758 POP_OBJECT (p, &i, A68G_LONG_INT);
759 PRELUDE_ERROR (D_ZERO (VALUE (&j)), p, ERROR_DIVISION_BY_ZERO, M_LONG_INT);
760 PUSH_VALUE (p, double_sdiv (p, VALUE (&i), VALUE (&j), 1), A68G_LONG_INT);
761 }
762
763 //! @brief OP / = (LONG INT, LONG INT) LONG REAL
764
765 void genie_div_double_int (NODE_T * p)
766 {
767 A68G_LONG_INT i, j;
768 POP_OBJECT (p, &j, A68G_LONG_INT);
769 POP_OBJECT (p, &i, A68G_LONG_INT);
770 PRELUDE_ERROR (D_ZERO (VALUE (&j)), p, ERROR_DIVISION_BY_ZERO, M_LONG_INT);
771 DOUBLE_NUM_T u, v, w;
772 v = double_int_to_double (p, VALUE (&j));
773 u = double_int_to_double (p, VALUE (&i));
774 w.f = u.f / v.f;
775 PUSH_VALUE (p, w, A68G_LONG_REAL);
776 }
777
778 //! @brief OP ** = (LONG INT, INT) INT
779
780 void genie_pow_double_int_int (NODE_T * p)
781 {
782 A68G_LONG_INT i; A68G_INT j;
783 POP_OBJECT (p, &j, A68G_INT);
784 PRELUDE_ERROR (VALUE (&j) < 0, p, ERROR_EXPONENT_INVALID, M_INT);
785 POP_OBJECT (p, &i, A68G_LONG_INT);
786 DOUBLE_NUM_T mult = VALUE (&i), prod;
787 set_lw (prod, 1);
788 UNSIGNED_T top = (UNSIGNED_T) VALUE (&j), expo = 1;
789 while (expo <= top) {
790 if (expo & top) {
791 prod = double_smul (p, prod, mult);
792 }
793 expo <<= 1;
794 if (expo <= top) {
795 mult = double_smul (p, mult, mult);
796 }
797 }
798 PUSH_VALUE (p, prod, A68G_LONG_INT);
799 }
800
801 //! @brief OP - = (LONG REAL) LONG REAL
802
803 void genie_minus_double (NODE_T * p)
804 {
805 A68G_LONG_REAL *u;
806 POP_OPERAND_ADDRESS (p, u, A68G_LONG_REAL);
807 VALUE (u).f = -(VALUE (u).f);
808 }
809
810 //! @brief OP ABS = (LONG REAL) LONG REAL
811
812 void genie_abs_double (NODE_T * p)
813 {
814 A68G_LONG_REAL *u;
815 POP_OPERAND_ADDRESS (p, u, A68G_LONG_REAL);
816 VALUE (u).f = fabs_double (VALUE (u).f);
817 }
818
819 //! @brief OP SIGN = (LONG REAL) INT
820
821 void genie_sign_double (NODE_T * p)
822 {
823 A68G_LONG_REAL u;
824 POP_OBJECT (p, &u, A68G_LONG_REAL);
825 PUSH_VALUE (p, sign_double (VALUE (&u)), A68G_INT);
826 }
827
828 //! @brief OP ** = (LONG REAL, INT) INT
829
830 void genie_pow_double_int (NODE_T * p)
831 {
832 A68G_INT j;
833 POP_OBJECT (p, &j, A68G_INT);
834 INT_T top = (INT_T) VALUE (&j);
835 A68G_LONG_REAL z;
836 POP_OBJECT (p, &z, A68G_LONG_INT);
837 DOUBLE_NUM_T mult, prod;
838 prod.f = 1.0q;
839 mult.f = VALUE (&z).f;
840 int negative;
841 if (top < 0) {
842 top = -top;
843 negative = A68G_TRUE;
844 } else {
845 negative = A68G_FALSE;
846 }
847 UNSIGNED_T expo = 1;
848 while (expo <= top) {
849 if (expo & top) {
850 prod.f = prod.f * mult.f;
851 CHECK_DOUBLE_REAL (p, prod.f);
852 }
853 expo <<= 1;
854 if (expo <= top) {
855 mult.f = mult.f * mult.f;
856 CHECK_DOUBLE_REAL (p, mult.f);
857 }
858 }
859 if (negative) {
860 prod.f = 1.0q / prod.f;
861 }
862 PUSH_VALUE (p, prod, A68G_LONG_REAL);
863 }
864
865 //! @brief OP ** = (LONG REAL, LONG REAL) LONG REAL
866
867 void genie_pow_double (NODE_T * p)
868 {
869 A68G_LONG_REAL x, y;
870 POP_OBJECT (p, &y, A68G_LONG_REAL);
871 POP_OBJECT (p, &x, A68G_LONG_REAL);
872 errno = 0;
873 PRELUDE_ERROR (VALUE (&x).f < 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
874 DOUBLE_T z = 0.0q;
875 if (VALUE (&x).f == 0.0q) {
876 if (VALUE (&y).f < 0.0q) {
877 errno = ERANGE;
878 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
879 } else {
880 z = (VALUE (&y).f == 0.0q ? 1.0q : 0.0q);
881 }
882 } else {
883 z = exp_double (VALUE (&y).f * log_double (VALUE (&x).f));
884 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
885 }
886 PUSH_VALUE (p, dble (z), A68G_LONG_REAL);
887 }
888
889 //! @brief OP + = (LONG REAL, LONG REAL) LONG REAL
890
891 void genie_add_double (NODE_T * p)
892 {
893 A68G_LONG_REAL u, v;
894 POP_OBJECT (p, &v, A68G_LONG_REAL);
895 POP_OBJECT (p, &u, A68G_LONG_REAL);
896 DOUBLE_NUM_T w;
897 w.f = VALUE (&u).f + VALUE (&v).f;
898 CHECK_DOUBLE_REAL (p, w.f);
899 PUSH_VALUE (p, w, A68G_LONG_REAL);
900 }
901
902 //! @brief OP - = (LONG REAL, LONG REAL) LONG REAL
903
904 void genie_sub_double (NODE_T * p)
905 {
906 A68G_LONG_REAL u, v;
907 POP_OBJECT (p, &v, A68G_LONG_REAL);
908 POP_OBJECT (p, &u, A68G_LONG_REAL);
909 DOUBLE_NUM_T w;
910 w.f = VALUE (&u).f - VALUE (&v).f;
911 CHECK_DOUBLE_REAL (p, w.f);
912 PUSH_VALUE (p, w, A68G_LONG_REAL);
913 }
914
915 //! @brief OP * = (LONG REAL, LONG REAL) LONG REAL
916
917 void genie_mul_double (NODE_T * p)
918 {
919 A68G_LONG_REAL u, v;
920 POP_OBJECT (p, &v, A68G_LONG_REAL);
921 POP_OBJECT (p, &u, A68G_LONG_REAL);
922 DOUBLE_NUM_T w;
923 w.f = VALUE (&u).f * VALUE (&v).f;
924 CHECK_DOUBLE_REAL (p, w.f);
925 PUSH_VALUE (p, w, A68G_LONG_REAL);
926 }
927
928 //! @brief OP / = (LONG REAL, LONG REAL) LONG REAL
929
930 void genie_over_double (NODE_T * p)
931 {
932 A68G_LONG_REAL u, v;
933 POP_OBJECT (p, &v, A68G_LONG_REAL);
934 POP_OBJECT (p, &u, A68G_LONG_REAL);
935 PRELUDE_ERROR (VALUE (&v).f == 0.0q, p, ERROR_DIVISION_BY_ZERO, M_LONG_REAL);
936 DOUBLE_NUM_T w;
937 w.f = VALUE (&u).f / VALUE (&v).f;
938 PUSH_VALUE (p, w, A68G_LONG_REAL);
939 }
940
941 //! @brief OP +:= = (REF LONG INT, LONG INT) REF LONG INT
942
943 void genie_plusab_double_int (NODE_T * p)
944 {
945 genie_f_and_becomes (p, M_REF_LONG_INT, genie_add_double_int);
946 }
947
948 //! @brief OP -:= = (REF LONG INT, LONG INT) REF LONG INT
949
950 void genie_minusab_double_int (NODE_T * p)
951 {
952 genie_f_and_becomes (p, M_REF_LONG_INT, genie_sub_double_int);
953 }
954
955 //! @brief OP *:= = (REF LONG INT, LONG INT) REF LONG INT
956
957 void genie_timesab_double_int (NODE_T * p)
958 {
959 genie_f_and_becomes (p, M_REF_LONG_INT, genie_mul_double_int);
960 }
961
962 //! @brief OP %:= = (REF LONG INT, LONG INT) REF LONG INT
963
964 void genie_overab_double_int (NODE_T * p)
965 {
966 genie_f_and_becomes (p, M_REF_LONG_INT, genie_over_double_int);
967 }
968
969 //! @brief OP %*:= = (REF LONG INT, LONG INT) REF LONG INT
970
971 void genie_modab_double_int (NODE_T * p)
972 {
973 genie_f_and_becomes (p, M_REF_LONG_INT, genie_mod_double_int);
974 }
975
976 //! @brief OP +:= = (REF LONG REAL, LONG REAL) REF LONG REAL
977
978 void genie_plusab_double (NODE_T * p)
979 {
980 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_add_double);
981 }
982
983 //! @brief OP -:= = (REF LONG REAL, LONG REAL) REF LONG REAL
984
985 void genie_minusab_double (NODE_T * p)
986 {
987 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_sub_double);
988 }
989
990 //! @brief OP *:= = (REF LONG REAL, LONG REAL) REF LONG REAL
991
992 void genie_timesab_double (NODE_T * p)
993 {
994 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_mul_double);
995 }
996
997 //! @brief OP /:= = (REF LONG REAL, LONG REAL) REF LONG REAL
998
999 void genie_divab_double (NODE_T * p)
1000 {
1001 genie_f_and_becomes (p, M_REF_LONG_REAL, genie_over_double);
1002 }
1003
1004 // OP (LONG INT, LONG INT) BOOL.
1005
1006 #define A68G_CMP_INT(n, OP)\
1007 void n (NODE_T * p) {\
1008 A68G_LONG_INT i, j;\
1009 POP_OBJECT (p, &j, A68G_LONG_INT);\
1010 POP_OBJECT (p, &i, A68G_LONG_INT);\
1011 DOUBLE_NUM_T w = double_ssub (p, VALUE (&i), VALUE (&j));\
1012 int k = sign_double_int (w);\
1013 PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
1014 }
1015
1016 A68G_CMP_INT (genie_eq_double_int, ==);
1017 A68G_CMP_INT (genie_ne_double_int, !=);
1018 A68G_CMP_INT (genie_lt_double_int, <);
1019 A68G_CMP_INT (genie_gt_double_int, >);
1020 A68G_CMP_INT (genie_le_double_int, <=);
1021 A68G_CMP_INT (genie_ge_double_int, >=);
1022
1023 // OP (LONG REAL, LONG REAL) BOOL.
1024 #define A68G_CMP_REAL(n, OP)\
1025 void n (NODE_T * p) {\
1026 A68G_LONG_REAL i, j;\
1027 POP_OBJECT (p, &j, A68G_LONG_REAL);\
1028 POP_OBJECT (p, &i, A68G_LONG_REAL);\
1029 PUSH_VALUE (p, (BOOL_T) (VALUE (&i).f OP VALUE (&j).f), A68G_BOOL);\
1030 }
1031
1032 A68G_CMP_REAL (genie_eq_double, ==);
1033 A68G_CMP_REAL (genie_ne_double, !=);
1034 A68G_CMP_REAL (genie_lt_double, <);
1035 A68G_CMP_REAL (genie_gt_double, >);
1036 A68G_CMP_REAL (genie_le_double, <=);
1037 A68G_CMP_REAL (genie_ge_double, >=);
1038
1039 //! @brief OP NOT = (LONG BITS) LONG BITS
1040
1041 void genie_not_double_bits (NODE_T * p)
1042 {
1043 A68G_LONG_BITS i;
1044 POP_OBJECT (p, &i, A68G_LONG_BITS);
1045 DOUBLE_NUM_T w;
1046 HW (w) = ~HW (VALUE (&i));
1047 LW (w) = ~LW (VALUE (&i));
1048 PUSH_VALUE (p, w, A68G_LONG_BITS);
1049 }
1050
1051 //! @brief OP = = (LONG BITS, LONG BITS) BOOL.
1052
1053 void genie_eq_double_bits (NODE_T * p)
1054 {
1055 A68G_LONG_BITS i, j;
1056 POP_OBJECT (p, &j, A68G_LONG_BITS);
1057 POP_OBJECT (p, &i, A68G_LONG_BITS);
1058 BOOL_T u = HW (VALUE (&i)) == HW (VALUE (&j));
1059 BOOL_T v = LW (VALUE (&i)) == LW (VALUE (&j));
1060 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1061 }
1062
1063 //! @brief OP ~= = (LONG BITS, LONG BITS) BOOL.
1064
1065 void genie_ne_double_bits (NODE_T * p)
1066 {
1067 A68G_LONG_BITS i, j;
1068 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i ~= j) == ~ (i = j)
1069 POP_OBJECT (p, &i, A68G_LONG_BITS);
1070 BOOL_T u = HW (VALUE (&i)) == HW (VALUE (&j));
1071 BOOL_T v = LW (VALUE (&i)) == LW (VALUE (&j));
1072 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_FALSE : A68G_TRUE), A68G_BOOL);
1073 }
1074
1075 //! @brief OP <= = (LONG BITS, LONG BITS) BOOL
1076
1077 void genie_le_double_bits (NODE_T * p)
1078 {
1079 A68G_LONG_BITS i, j;
1080 POP_OBJECT (p, &j, A68G_LONG_BITS);
1081 POP_OBJECT (p, &i, A68G_LONG_BITS);
1082 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&j));
1083 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&j));
1084 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1085 }
1086
1087 //! @brief OP > = (LONG BITS, LONG BITS) BOOL
1088
1089 void genie_gt_double_bits (NODE_T * p)
1090 {
1091 A68G_LONG_BITS i, j;
1092 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i > j) == ! (i <= j)
1093 POP_OBJECT (p, &i, A68G_LONG_BITS);
1094 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&j));
1095 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&j));
1096 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_FALSE : A68G_TRUE), A68G_BOOL);
1097 }
1098
1099 //! @brief OP >= = (LONG BITS, LONG BITS) BOOL
1100
1101 void genie_ge_double_bits (NODE_T * p)
1102 {
1103 A68G_LONG_BITS i, j;
1104 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i >= j) == (j <= i)
1105 POP_OBJECT (p, &i, A68G_LONG_BITS);
1106 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&i));
1107 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&i));
1108 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1109 }
1110
1111 //! @brief OP < = (LONG BITS, LONG BITS) BOOL
1112
1113 void genie_lt_double_bits (NODE_T * p)
1114 {
1115 A68G_LONG_BITS i, j;
1116 POP_OBJECT (p, &j, A68G_LONG_BITS); // (i < j) == ! (i >= j)
1117 POP_OBJECT (p, &i, A68G_LONG_BITS);
1118 BOOL_T u = (HW (VALUE (&i)) | HW (VALUE (&j))) == HW (VALUE (&i));
1119 BOOL_T v = (LW (VALUE (&i)) | LW (VALUE (&j))) == LW (VALUE (&i));
1120 PUSH_VALUE (p, (BOOL_T) (u & v ? A68G_FALSE : A68G_TRUE), A68G_BOOL);
1121 }
1122
1123 //! @brief PROC long bits pack = ([] BOOL) BITS
1124
1125 void genie_double_bits_pack (NODE_T * p)
1126 {
1127 A68G_REF z;
1128 POP_REF (p, &z);
1129 CHECK_REF (p, z, M_ROW_BOOL);
1130 A68G_ARRAY *arr; A68G_TUPLE *tup;
1131 GET_DESCRIPTOR (arr, tup, &z);
1132 size_t size = ROW_SIZE (tup);
1133 PRELUDE_ERROR (size < 0 || size > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_ROW_BOOL);
1134 DOUBLE_NUM_T w;
1135 set_lw (w, 0x0);
1136 if (ROW_SIZE (tup) > 0) {
1137 UNSIGNED_T bit = 0x0;
1138 BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
1139 int n = 0;
1140 for (int k = UPB (tup); k >= LWB (tup); k--) {
1141 A68G_BOOL *boo = (A68G_BOOL *) & (base[INDEX_1_DIM (arr, tup, k)]);
1142 CHECK_INIT (p, INITIALISED (boo), M_BOOL);
1143 if (n == 0 || n == A68G_BITS_WIDTH) {
1144 bit = 0x1;
1145 }
1146 if (VALUE (boo)) {
1147 if (n < A68G_BITS_WIDTH) {
1148 LW (w) |= bit;
1149 } else {
1150 HW (w) |= bit;
1151 };
1152 }
1153 n++;
1154 bit <<= 1;
1155 }
1156 }
1157 PUSH_VALUE (p, w, A68G_LONG_BITS);
1158 }
1159
1160 //! @brief OP AND = (LONG BITS, LONG BITS) LONG BITS
1161
1162 void genie_and_double_bits (NODE_T * p)
1163 {
1164 A68G_LONG_BITS i, j;
1165 POP_OBJECT (p, &j, A68G_LONG_BITS);
1166 POP_OBJECT (p, &i, A68G_LONG_BITS);
1167 DOUBLE_NUM_T w;
1168 HW (w) = HW (VALUE (&i)) & HW (VALUE (&j));
1169 LW (w) = LW (VALUE (&i)) & LW (VALUE (&j));
1170 PUSH_VALUE (p, w, A68G_LONG_BITS);
1171 }
1172
1173 //! @brief OP OR = (LONG BITS, LONG BITS) LONG BITS
1174
1175 void genie_or_double_bits (NODE_T * p)
1176 {
1177 A68G_LONG_BITS i, j;
1178 POP_OBJECT (p, &j, A68G_LONG_BITS);
1179 POP_OBJECT (p, &i, A68G_LONG_BITS);
1180 DOUBLE_NUM_T w;
1181 HW (w) = HW (VALUE (&i)) | HW (VALUE (&j));
1182 LW (w) = LW (VALUE (&i)) | LW (VALUE (&j));
1183 PUSH_VALUE (p, w, A68G_LONG_BITS);
1184 }
1185
1186 //! @brief OP XOR = (LONG BITS, LONG BITS) LONG BITS
1187
1188 void genie_xor_double_bits (NODE_T * p)
1189 {
1190 A68G_LONG_BITS i, j;
1191 POP_OBJECT (p, &j, A68G_LONG_BITS);
1192 POP_OBJECT (p, &i, A68G_LONG_BITS);
1193 DOUBLE_NUM_T w;
1194 HW (w) = HW (VALUE (&i)) ^ HW (VALUE (&j));
1195 LW (w) = LW (VALUE (&i)) ^ LW (VALUE (&j));
1196 PUSH_VALUE (p, w, A68G_LONG_BITS);
1197 }
1198
1199 //! @brief OP + = (LONG BITS, LONG BITS) LONG BITS
1200
1201 void genie_add_double_bits (NODE_T * p)
1202 {
1203 A68G_LONG_BITS i, j;
1204 POP_OBJECT (p, &j, A68G_LONG_BITS);
1205 POP_OBJECT (p, &i, A68G_LONG_BITS);
1206 DOUBLE_NUM_T w;
1207 add_double (p, M_LONG_BITS, w, VALUE (&i), VALUE (&j));
1208 PUSH_VALUE (p, w, A68G_LONG_BITS);
1209 }
1210
1211 //! @brief OP - = (LONG BITS, LONG BITS) LONG BITS
1212
1213 void genie_sub_double_bits (NODE_T * p)
1214 {
1215 A68G_LONG_BITS i, j;
1216 POP_OBJECT (p, &j, A68G_LONG_BITS);
1217 POP_OBJECT (p, &i, A68G_LONG_BITS);
1218 DOUBLE_NUM_T w;
1219 sub_double (p, M_LONG_BITS, w, VALUE (&i), VALUE (&j));
1220 PUSH_VALUE (p, w, A68G_LONG_BITS);
1221 }
1222
1223 //! @brief OP * = (LONG BITS, LONG BITS) LONG BITS
1224
1225 void genie_times_double_bits (NODE_T * p)
1226 {
1227 A68G_LONG_BITS i, j;
1228 POP_OBJECT (p, &j, A68G_LONG_BITS);
1229 POP_OBJECT (p, &i, A68G_LONG_BITS);
1230 DOUBLE_NUM_T w = double_umul (p, M_LONG_BITS, VALUE (&i), VALUE (&j));
1231 PUSH_VALUE (p, w, A68G_LONG_BITS);
1232 }
1233
1234 //! @brief OP OVER = (LONG BITS, LONG BITS) LONG BITS
1235
1236 void genie_over_double_bits (NODE_T * p)
1237 {
1238 A68G_LONG_BITS i, j;
1239 POP_OBJECT (p, &j, A68G_LONG_BITS);
1240 POP_OBJECT (p, &i, A68G_LONG_BITS);
1241 DOUBLE_NUM_T w = double_udiv (p, M_LONG_BITS, VALUE (&i), VALUE (&j), 0);
1242 PUSH_VALUE (p, w, A68G_LONG_BITS);
1243 }
1244
1245 //! @brief OP MOD = (LONG BITS, LONG BITS) LONG BITS
1246
1247 void genie_mod_double_bits (NODE_T * p)
1248 {
1249 A68G_LONG_BITS i, j;
1250 DOUBLE_NUM_T w;
1251 POP_OBJECT (p, &j, A68G_LONG_BITS);
1252 POP_OBJECT (p, &i, A68G_LONG_BITS);
1253 w = double_udiv (p, M_LONG_BITS, VALUE (&i), VALUE (&j), 1);
1254 PUSH_VALUE (p, w, A68G_LONG_BITS);
1255 }
1256
1257 //! @brief OP ELEM = (INT, LONG BITS) BOOL
1258
1259 void genie_elem_double_bits (NODE_T * p)
1260 {
1261 A68G_LONG_BITS j; A68G_INT i;
1262 POP_OBJECT (p, &j, A68G_LONG_BITS);
1263 POP_OBJECT (p, &i, A68G_INT);
1264 int k = VALUE (&i);
1265 PRELUDE_ERROR (k < 1 || k > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1266 UNSIGNED_T mask = 0x1, *w;
1267 if (k <= A68G_BITS_WIDTH) {
1268 w = &(HW (VALUE (&j)));
1269 } else {
1270 w = &(LW (VALUE (&j)));
1271 k -= A68G_BITS_WIDTH;
1272 }
1273 for (int n = 0; n < A68G_BITS_WIDTH - k; n++) {
1274 mask = mask << 1;
1275 }
1276 PUSH_VALUE (p, (BOOL_T) ((*w & mask) ? A68G_TRUE : A68G_FALSE), A68G_BOOL);
1277 }
1278
1279 //! @brief OP SET = (INT, LONG BITS) LONG BITS
1280
1281 void genie_set_double_bits (NODE_T * p)
1282 {
1283 A68G_LONG_BITS j; A68G_INT i;
1284 POP_OBJECT (p, &j, A68G_LONG_BITS);
1285 POP_OBJECT (p, &i, A68G_INT);
1286 int k = VALUE (&i);
1287 PRELUDE_ERROR (k < 1 || k > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1288 UNSIGNED_T mask = 0x1, *w;
1289 if (k <= A68G_BITS_WIDTH) {
1290 w = &(HW (VALUE (&j)));
1291 } else {
1292 w = &(LW (VALUE (&j)));
1293 k -= A68G_BITS_WIDTH;
1294 }
1295 for (int n = 0; n < A68G_BITS_WIDTH - k; n++) {
1296 mask = mask << 1;
1297 }
1298 (*w) |= mask;
1299 PUSH_OBJECT (p, j, A68G_LONG_BITS);
1300 }
1301
1302 //! @brief OP CLEAR = (INT, LONG BITS) LONG BITS
1303
1304 void genie_clear_double_bits (NODE_T * p)
1305 {
1306 A68G_LONG_BITS j; A68G_INT i;
1307 POP_OBJECT (p, &j, A68G_LONG_BITS);
1308 POP_OBJECT (p, &i, A68G_INT);
1309 int k = VALUE (&i);
1310 PRELUDE_ERROR (k < 1 || k > A68G_LONG_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1311 UNSIGNED_T mask = 0x1, *w;
1312 if (k <= A68G_BITS_WIDTH) {
1313 w = &(HW (VALUE (&j)));
1314 } else {
1315 w = &(LW (VALUE (&j)));
1316 k -= A68G_BITS_WIDTH;
1317 }
1318 for (int n = 0; n < A68G_BITS_WIDTH - k; n++) {
1319 mask = mask << 1;
1320 }
1321 (*w) &= ~mask;
1322 PUSH_OBJECT (p, j, A68G_LONG_BITS);
1323 }
1324
1325 //! @brief OP SHL = (LONG BITS, INT) LONG BITS
1326
1327 void genie_shl_double_bits (NODE_T * p)
1328 {
1329 A68G_LONG_BITS i; A68G_INT j;
1330 POP_OBJECT (p, &j, A68G_INT);
1331 POP_OBJECT (p, &i, A68G_LONG_BITS);
1332 DOUBLE_NUM_T *w = &VALUE (&i);
1333 int k = VALUE (&j);
1334 if (VALUE (&j) >= 0) {
1335 for (int n = 0; n < k; n++) {
1336 UNSIGNED_T carry = ((LW (*w) & D_SIGN) ? 0x1 : 0x0);
1337 PRELUDE_ERROR (MODCHK (p, M_LONG_BITS, HW (*w) & D_SIGN), p, ERROR_MATH, M_LONG_BITS);
1338 HW (*w) = (HW (*w) << 1) | carry;
1339 LW (*w) = (LW (*w) << 1);
1340 }
1341 } else {
1342 k = -k;
1343 for (int n = 0; n < k; n++) {
1344 UNSIGNED_T carry = ((HW (*w) & 0x1) ? D_SIGN : 0x0);
1345 HW (*w) = (HW (*w) >> 1);
1346 LW (*w) = (LW (*w) >> 1) | carry;
1347 }
1348 }
1349 PUSH_OBJECT (p, i, A68G_LONG_BITS);
1350 }
1351
1352 //! @brief OP SHR = (LONG BITS, INT) LONG BITS
1353
1354 void genie_shr_double_bits (NODE_T * p)
1355 {
1356 A68G_INT *j;
1357 POP_OPERAND_ADDRESS (p, j, A68G_INT);
1358 VALUE (j) = -VALUE (j);
1359 genie_shl_double_bits (p); // Conform RR
1360 }
1361
1362 //! @brief OP ROL = (LONG BITS, INT) LONG BITS
1363
1364 void genie_rol_double_bits (NODE_T * p)
1365 {
1366 A68G_LONG_BITS i; A68G_INT j;
1367 DOUBLE_NUM_T *w = &VALUE (&i);
1368 POP_OBJECT (p, &j, A68G_INT);
1369 POP_OBJECT (p, &i, A68G_LONG_BITS);
1370 int k = VALUE (&j);
1371 if (k >= 0) {
1372 for (int n = 0; n < k; n++) {
1373 UNSIGNED_T carry = ((HW (*w) & D_SIGN) ? 0x1 : 0x0);
1374 UNSIGNED_T carry_between = ((LW (*w) & D_SIGN) ? 0x1 : 0x0);
1375 HW (*w) = (HW (*w) << 1) | carry_between;
1376 LW (*w) = (LW (*w) << 1) | carry;
1377 }
1378 } else {
1379 k = -k;
1380 for (int n = 0; n < k; n++) {
1381 UNSIGNED_T carry = ((LW (*w) & 0x1) ? D_SIGN : 0x0);
1382 UNSIGNED_T carry_between = ((HW (*w) & 0x1) ? D_SIGN : 0x0);
1383 HW (*w) = (HW (*w) >> 1) | carry;
1384 LW (*w) = (LW (*w) >> 1) | carry_between;
1385 }
1386 }
1387 PUSH_OBJECT (p, i, A68G_LONG_BITS);
1388 }
1389
1390 //! @brief OP ROR = (LONG BITS, INT) LONG BITS
1391
1392 void genie_ror_double_bits (NODE_T * p)
1393 {
1394 A68G_INT *j;
1395 POP_OPERAND_ADDRESS (p, j, A68G_INT);
1396 VALUE (j) = -VALUE (j);
1397 genie_rol_double_bits (p); // Conform RR
1398 }
1399
1400 //! @brief OP BIN = (LONG INT) LONG BITS
1401
1402 void genie_bin_double_int (NODE_T * p)
1403 {
1404 A68G_LONG_INT i;
1405 POP_OBJECT (p, &i, A68G_LONG_INT);
1406 // RR does not convert negative numbers
1407 if (D_NEG (VALUE (&i))) {
1408 errno = EDOM;
1409 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, M_BITS);
1410 exit_genie (p, A68G_RUNTIME_ERROR);
1411 }
1412 PUSH_OBJECT (p, i, A68G_LONG_BITS);
1413 }
1414
1415 //! @brief OP +* = (LONG REAL, LONG REAL) LONG COMPLEX
1416
1417 void genie_i_double_compl (NODE_T * p)
1418 {
1419 (void) p;
1420 }
1421
1422 //! @brief OP SHORTEN = (LONG COMPLEX) COMPLEX
1423
1424 void genie_shorten_double_compl_to_complex (NODE_T * p)
1425 {
1426 A68G_LONG_REAL re, im;
1427 POP_OBJECT (p, &im, A68G_LONG_REAL);
1428 POP_OBJECT (p, &re, A68G_LONG_REAL);
1429 REAL_T w = VALUE (&re).f;
1430 PUSH_VALUE (p, w, A68G_REAL);
1431 w = VALUE (&im).f;
1432 PUSH_VALUE (p, w, A68G_REAL);
1433 }
1434
1435 //! @brief OP LENG = (LONG COMPLEX) LONG LONG COMPLEX
1436
1437 void genie_lengthen_double_compl_to_long_mp_complex (NODE_T * p)
1438 {
1439 int digs = DIGITS (M_LONG_LONG_REAL);
1440 A68G_LONG_REAL re, im;
1441 POP_OBJECT (p, &im, A68G_LONG_REAL);
1442 POP_OBJECT (p, &re, A68G_LONG_REAL);
1443 MP_T *z = nil_mp (p, digs);
1444 (void) double_to_mp (p, z, VALUE (&re).f, A68G_DOUBLE_DIG, A68G_FALSE, digs);
1445 MP_STATUS (z) = (MP_T) INIT_MASK;
1446 z = nil_mp (p, digs);
1447 (void) double_to_mp (p, z, VALUE (&im).f, A68G_DOUBLE_DIG, A68G_FALSE, digs);
1448 MP_STATUS (z) = (MP_T) INIT_MASK;
1449 }
1450
1451 //! @brief OP +* = (LONG INT, LONG INT) LONG COMPLEX
1452
1453 void genie_i_int_double_compl (NODE_T * p)
1454 {
1455 A68G_LONG_INT re, im;
1456 POP_OBJECT (p, &im, A68G_LONG_INT);
1457 POP_OBJECT (p, &re, A68G_LONG_INT);
1458 PUSH_VALUE (p, double_int_to_double (p, VALUE (&re)), A68G_LONG_REAL);
1459 PUSH_VALUE (p, double_int_to_double (p, VALUE (&im)), A68G_LONG_REAL);
1460 }
1461
1462 //! @brief OP RE = (LONG COMPLEX) LONG REAL
1463
1464 void genie_re_double_compl (NODE_T * p)
1465 {
1466 DECREMENT_STACK_POINTER (p, SIZE (M_LONG_REAL));
1467 }
1468
1469 //! @brief OP IM = (LONG COMPLEX) LONG REAL
1470
1471 void genie_im_double_compl (NODE_T * p)
1472 {
1473 A68G_LONG_REAL re, im;
1474 POP_OBJECT (p, &im, A68G_LONG_REAL);
1475 POP_OBJECT (p, &re, A68G_LONG_REAL);
1476 PUSH_OBJECT (p, im, A68G_LONG_REAL);
1477 }
1478
1479 //! @brief OP - = (LONG COMPLEX) LONG COMPLEX
1480
1481 void genie_minus_double_compl (NODE_T * p)
1482 {
1483 A68G_LONG_REAL re, im;
1484 POP_OBJECT (p, &im, A68G_LONG_REAL);
1485 POP_OBJECT (p, &re, A68G_LONG_REAL);
1486 VALUE (&re).f = -VALUE (&re).f;
1487 VALUE (&im).f = -VALUE (&im).f;
1488 PUSH_OBJECT (p, im, A68G_LONG_REAL);
1489 PUSH_OBJECT (p, re, A68G_LONG_REAL);
1490 }
1491
1492 //! @brief OP ABS = (LONG COMPLEX) LONG REAL
1493
1494 void genie_abs_double_compl (NODE_T * p)
1495 {
1496 A68G_LONG_REAL re, im;
1497 POP_LONG_COMPLEX (p, &re, &im);
1498 PUSH_VALUE (p, dble (a68g_hypot_double (VALUE (&re).f, VALUE (&im).f)), A68G_LONG_REAL);
1499 }
1500
1501 //! @brief OP ARG = (LONG COMPLEX) LONG REAL
1502
1503 void genie_arg_double_compl (NODE_T * p)
1504 {
1505 A68G_LONG_REAL re, im;
1506 POP_LONG_COMPLEX (p, &re, &im);
1507 PRELUDE_ERROR (VALUE (&re).f == 0.0q && VALUE (&im).f == 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_COMPLEX);
1508 PUSH_VALUE (p, dble (atan2_double (VALUE (&im).f, VALUE (&re).f)), A68G_LONG_REAL);
1509 }
1510
1511 //! @brief OP CONJ = (LONG COMPLEX) LONG COMPLEX
1512
1513 void genie_conj_double_compl (NODE_T * p)
1514 {
1515 A68G_LONG_REAL im;
1516 POP_OBJECT (p, &im, A68G_LONG_REAL);
1517 VALUE (&im).f = -VALUE (&im).f;
1518 PUSH_OBJECT (p, im, A68G_LONG_REAL);
1519 }
1520
1521 //! @brief OP + = (COMPLEX, COMPLEX) COMPLEX
1522
1523 void genie_add_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 VALUE (&re_x).f += VALUE (&re_y).f;
1529 VALUE (&im_x).f += VALUE (&im_y).f;
1530 CHECK_DOUBLE_COMPLEX (p, VALUE (&im_x).f, VALUE (&im_y).f);
1531 PUSH_OBJECT (p, re_x, A68G_LONG_REAL);
1532 PUSH_OBJECT (p, im_x, A68G_LONG_REAL);
1533 }
1534
1535 //! @brief OP - = (COMPLEX, COMPLEX) COMPLEX
1536
1537 void genie_sub_double_compl (NODE_T * p)
1538 {
1539 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1540 POP_LONG_COMPLEX (p, &re_y, &im_y);
1541 POP_LONG_COMPLEX (p, &re_x, &im_x);
1542 VALUE (&re_x).f -= VALUE (&re_y).f;
1543 VALUE (&im_x).f -= VALUE (&im_y).f;
1544 CHECK_DOUBLE_COMPLEX (p, VALUE (&im_x).f, VALUE (&im_y).f);
1545 PUSH_OBJECT (p, re_x, A68G_LONG_REAL);
1546 PUSH_OBJECT (p, im_x, A68G_LONG_REAL);
1547 }
1548
1549 //! @brief OP * = (COMPLEX, COMPLEX) COMPLEX
1550
1551 void genie_mul_double_compl (NODE_T * p)
1552 {
1553 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1554 POP_LONG_COMPLEX (p, &re_y, &im_y);
1555 POP_LONG_COMPLEX (p, &re_x, &im_x);
1556 DOUBLE_T re = VALUE (&re_x).f * VALUE (&re_y).f - VALUE (&im_x).f * VALUE (&im_y).f;
1557 DOUBLE_T im = VALUE (&im_x).f * VALUE (&re_y).f + VALUE (&re_x).f * VALUE (&im_y).f;
1558 CHECK_DOUBLE_COMPLEX (p, VALUE (&im_x).f, VALUE (&im_y).f);
1559 PUSH_VALUE (p, dble (re), A68G_LONG_REAL);
1560 PUSH_VALUE (p, dble (im), A68G_LONG_REAL);
1561 }
1562
1563 //! @brief OP / = (COMPLEX, COMPLEX) COMPLEX
1564
1565 void genie_div_double_compl (NODE_T * p)
1566 {
1567 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1568 DOUBLE_T re = 0.0, im = 0.0;
1569 POP_LONG_COMPLEX (p, &re_y, &im_y);
1570 POP_LONG_COMPLEX (p, &re_x, &im_x);
1571 PRELUDE_ERROR (VALUE (&re_y).f == 0.0q && VALUE (&im_y).f == 0.0q, p, ERROR_DIVISION_BY_ZERO, M_LONG_COMPLEX);
1572 if (ABSQ (VALUE (&re_y).f) >= ABSQ (VALUE (&im_y).f)) {
1573 DOUBLE_T r = VALUE (&im_y).f / VALUE (&re_y).f, den = VALUE (&re_y).f + r * VALUE (&im_y).f;
1574 re = (VALUE (&re_x).f + r * VALUE (&im_x).f) / den;
1575 im = (VALUE (&im_x).f - r * VALUE (&re_x).f) / den;
1576 } else {
1577 DOUBLE_T r = VALUE (&re_y).f / VALUE (&im_y).f, den = VALUE (&im_y).f + r * VALUE (&re_y).f;
1578 re = (VALUE (&re_x).f * r + VALUE (&im_x).f) / den;
1579 im = (VALUE (&im_x).f * r - VALUE (&re_x).f) / den;
1580 }
1581 PUSH_VALUE (p, dble (re), A68G_LONG_REAL);
1582 PUSH_VALUE (p, dble (im), A68G_LONG_REAL);
1583 }
1584
1585 //! @brief OP ** = (LONG COMPLEX, INT) LONG COMPLEX
1586
1587 void genie_pow_double_compl_int (NODE_T * p)
1588 {
1589 A68G_LONG_REAL re_x, im_x;
1590 A68G_INT j;
1591 BOOL_T negative;
1592 POP_OBJECT (p, &j, A68G_INT);
1593 POP_LONG_COMPLEX (p, &re_x, &im_x);
1594 DOUBLE_T re_z = 1.0q, im_z = 0.0q;
1595 DOUBLE_T re_y = VALUE (&re_x).f, im_y = VALUE (&im_x).f;
1596 negative = (BOOL_T) (VALUE (&j) < 0);
1597 if (negative) {
1598 VALUE (&j) = -VALUE (&j);
1599 }
1600 INT_T expo = 1;
1601 while ((UNSIGNED_T) expo <= (UNSIGNED_T) (VALUE (&j))) {
1602 DOUBLE_T z;
1603 if (expo & VALUE (&j)) {
1604 z = re_z * re_y - im_z * im_y;
1605 im_z = re_z * im_y + im_z * re_y;
1606 re_z = z;
1607 }
1608 z = re_y * re_y - im_y * im_y;
1609 im_y = im_y * re_y + re_y * im_y;
1610 re_y = z;
1611 CHECK_DOUBLE_COMPLEX (p, re_y, im_y);
1612 CHECK_DOUBLE_COMPLEX (p, re_z, im_z);
1613 expo <<= 1;
1614 }
1615 if (negative) {
1616 PUSH_VALUE (p, dble (1.0q), A68G_LONG_REAL);
1617 PUSH_VALUE (p, dble (0.0q), A68G_LONG_REAL);
1618 PUSH_VALUE (p, dble (re_z), A68G_LONG_REAL);
1619 PUSH_VALUE (p, dble (im_z), A68G_LONG_REAL);
1620 genie_div_double_compl (p);
1621 } else {
1622 PUSH_VALUE (p, dble (re_z), A68G_LONG_REAL);
1623 PUSH_VALUE (p, dble (im_z), A68G_LONG_REAL);
1624 }
1625 }
1626
1627 //! @brief OP = = (COMPLEX, COMPLEX) BOOL
1628
1629 void genie_eq_double_compl (NODE_T * p)
1630 {
1631 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1632 POP_LONG_COMPLEX (p, &re_y, &im_y);
1633 POP_LONG_COMPLEX (p, &re_x, &im_x);
1634 PUSH_VALUE (p, (BOOL_T) ((VALUE (&re_x).f == VALUE (&re_y).f) && (VALUE (&im_x).f == VALUE (&im_y).f)), A68G_BOOL);
1635 }
1636
1637 //! @brief OP /= = (COMPLEX, COMPLEX) BOOL
1638
1639 void genie_ne_double_compl (NODE_T * p)
1640 {
1641 A68G_LONG_REAL re_x, im_x, re_y, im_y;
1642 POP_LONG_COMPLEX (p, &re_y, &im_y);
1643 POP_LONG_COMPLEX (p, &re_x, &im_x);
1644 PUSH_VALUE (p, (BOOL_T) ! ((VALUE (&re_x).f == VALUE (&re_y).f) && (VALUE (&im_x).f == VALUE (&im_y).f)), A68G_BOOL);
1645 }
1646
1647 //! @brief OP +:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1648
1649 void genie_plusab_double_compl (NODE_T * p)
1650 {
1651 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_add_double_compl);
1652 }
1653
1654 //! @brief OP -:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1655
1656 void genie_minusab_double_compl (NODE_T * p)
1657 {
1658 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_sub_double_compl);
1659 }
1660
1661 //! @brief OP *:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1662
1663 void genie_timesab_double_compl (NODE_T * p)
1664 {
1665 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_mul_double_compl);
1666 }
1667
1668 //! @brief OP /:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1669
1670 void genie_divab_double_compl (NODE_T * p)
1671 {
1672 genie_f_and_becomes (p, M_REF_LONG_COMPLEX, genie_div_double_compl);
1673 }
1674
1675 //! @brief OP LENG = (COMPLEX) LONG COMPLEX
1676
1677 void genie_lengthen_complex_to_double_compl (NODE_T * p)
1678 {
1679 A68G_REAL i;
1680 POP_OBJECT (p, &i, A68G_REAL);
1681 genie_lengthen_real_to_double (p);
1682 PUSH_OBJECT (p, i, A68G_REAL);
1683 genie_lengthen_real_to_double (p);
1684 }
1685
1686 // Functions
1687
1688 #define CD_FUNCTION(name, fun)\
1689 void name (NODE_T * p) {\
1690 A68G_LONG_REAL *x;\
1691 POP_OPERAND_ADDRESS (p, x, A68G_LONG_REAL);\
1692 errno = 0;\
1693 VALUE (x).f = fun (VALUE (x).f);\
1694 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);\
1695 }
1696
1697 CD_FUNCTION (genie_acos_double, acos_double);
1698 CD_FUNCTION (genie_acosh_double, acosh_double);
1699 CD_FUNCTION (genie_asinh_double, asinh_double);
1700 CD_FUNCTION (genie_atanh_double, atanh_double);
1701 CD_FUNCTION (genie_asin_double, asin_double);
1702 CD_FUNCTION (genie_atan_double, atan_double);
1703 CD_FUNCTION (genie_cosh_double, cosh_double);
1704 CD_FUNCTION (genie_cos_double, cos_double);
1705 CD_FUNCTION (genie_curt_double, cbrt_double);
1706 CD_FUNCTION (genie_exp_double, exp_double);
1707 CD_FUNCTION (genie_ln_double, log_double);
1708 CD_FUNCTION (genie_log_double, log10_double);
1709 CD_FUNCTION (genie_sinh_double, sinh_double);
1710 CD_FUNCTION (genie_sin_double, sin_double);
1711 CD_FUNCTION (genie_sqrt_double, sqrt_double);
1712 CD_FUNCTION (genie_tanh_double, tanh_double);
1713 CD_FUNCTION (genie_tan_double, tan_double);
1714 CD_FUNCTION (genie_erf_double, erf_double);
1715 CD_FUNCTION (genie_erfc_double, erfc_double);
1716 CD_FUNCTION (genie_lngamma_double, lgamma_double);
1717 CD_FUNCTION (genie_gamma_double, tgamma_double);
1718 CD_FUNCTION (genie_csc_double, a68g_csc_double);
1719 CD_FUNCTION (genie_cscdg_double, a68g_cscdg_double);
1720 CD_FUNCTION (genie_acsc_double, a68g_acsc_double);
1721 CD_FUNCTION (genie_acscdg_double, a68g_acscdg_double);
1722 CD_FUNCTION (genie_sec_double, a68g_sec_double);
1723 CD_FUNCTION (genie_secdg_double, a68g_secdg_double);
1724 CD_FUNCTION (genie_asec_double, a68g_asec_double);
1725 CD_FUNCTION (genie_asecdg_double, a68g_asecdg_double);
1726 CD_FUNCTION (genie_cot_double, a68g_cot_double);
1727 CD_FUNCTION (genie_acot_double, a68g_acot_double);
1728 CD_FUNCTION (genie_sindg_double, a68g_sindg_double);
1729 CD_FUNCTION (genie_cas_double, a68g_cas_double);
1730 CD_FUNCTION (genie_cosdg_double, a68g_cosdg_double);
1731 CD_FUNCTION (genie_tandg_double, a68g_tandg_double);
1732 CD_FUNCTION (genie_asindg_double, a68g_asindg_double);
1733 CD_FUNCTION (genie_acosdg_double, a68g_acosdg_double);
1734 CD_FUNCTION (genie_atandg_double, a68g_atandg_double);
1735 CD_FUNCTION (genie_cotdg_double, a68g_cotdg_double);
1736 CD_FUNCTION (genie_acotdg_double, a68g_acotdg_double);
1737 CD_FUNCTION (genie_sinpi_double, a68g_sinpi_double);
1738 CD_FUNCTION (genie_cospi_double, a68g_cospi_double);
1739 CD_FUNCTION (genie_tanpi_double, a68g_tanpi_double);
1740 CD_FUNCTION (genie_cotpi_double, a68g_cotpi_double);
1741
1742 //! @brief PROC long arctan2 = (LONG REAL) LONG REAL
1743
1744 void genie_atan2_double (NODE_T * p)
1745 {
1746 A68G_LONG_REAL x, y;
1747 POP_OBJECT (p, &y, A68G_LONG_REAL);
1748 POP_OBJECT (p, &x, A68G_LONG_REAL);
1749 errno = 0;
1750 PRELUDE_ERROR (VALUE (&x).f == 0.0q && VALUE (&y).f == 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
1751 VALUE (&x).f = a68g_atan2_real (VALUE (&y).f, VALUE (&x).f);
1752 PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
1753 PUSH_OBJECT (p, x, A68G_LONG_REAL);
1754 }
1755
1756 //! @brief PROC long arctan2dg = (LONG REAL) LONG REAL
1757
1758 void genie_atan2dg_double (NODE_T * p)
1759 {
1760 A68G_LONG_REAL x, y;
1761 POP_OBJECT (p, &y, A68G_LONG_REAL);
1762 POP_OBJECT (p, &x, A68G_LONG_REAL);
1763 errno = 0;
1764 PRELUDE_ERROR (VALUE (&x).f == 0.0q && VALUE (&y).f == 0.0q, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
1765 VALUE (&x).f = CONST_180_OVER_PI_Q * a68g_atan2_real (VALUE (&y).f, VALUE (&x).f);
1766 PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
1767 PUSH_OBJECT (p, x, A68G_LONG_REAL);
1768 }
1769
1770 //! @brief PROC (LONG REAL) LONG REAL inverf
1771
1772 void genie_inverf_double (NODE_T * _p_)
1773 {
1774 A68G_LONG_REAL x;
1775 DOUBLE_T y, z;
1776 POP_OBJECT (_p_, &x, A68G_LONG_REAL);
1777 errno = 0;
1778 y = VALUE (&x).f;
1779 z = inverf_double (y);
1780 MATH_RTE (_p_, errno != 0, M_LONG_REAL, NO_TEXT);
1781 CHECK_DOUBLE_REAL (_p_, z);
1782 PUSH_VALUE (_p_, dble (z), A68G_LONG_REAL);
1783 }
1784
1785 //! @brief PROC (LONG REAL) LONG REAL inverfc
1786
1787 void genie_inverfc_double (NODE_T * p)
1788 {
1789 A68G_LONG_REAL *u;
1790 POP_OPERAND_ADDRESS (p, u, A68G_LONG_REAL);
1791 VALUE (u).f = 1.0q - (VALUE (u).f);
1792 genie_inverf_double (p);
1793 }
1794
1795 #define CD_C_FUNCTION(p, g)\
1796 A68G_LONG_REAL re, im;\
1797 DOUBLE_COMPLEX_T z;\
1798 POP_OBJECT (p, &im, A68G_LONG_REAL);\
1799 POP_OBJECT (p, &re, A68G_LONG_REAL);\
1800 errno = 0;\
1801 z = VALUE (&re).f + VALUE (&im).f * _Complex_I;\
1802 z = g (z);\
1803 PUSH_VALUE (p, dble ((DOUBLE_T) creal_double (z)), A68G_LONG_REAL);\
1804 PUSH_VALUE (p, dble ((DOUBLE_T) cimag_double (z)), A68G_LONG_REAL);\
1805 MATH_RTE (p, errno != 0, M_COMPLEX, NO_TEXT);
1806
1807 //! @brief PROC long csqrt = (LONG COMPLEX) LONG COMPLEX
1808
1809 void genie_sqrt_double_compl (NODE_T * p)
1810 {
1811 CD_C_FUNCTION (p, csqrt_double);
1812 }
1813
1814 //! @brief PROC long csin = (LONG COMPLEX) LONG COMPLEX
1815
1816 void genie_sin_double_compl (NODE_T * p)
1817 {
1818 CD_C_FUNCTION (p, csin_double);
1819 }
1820
1821 //! @brief PROC long ccos = (LONG COMPLEX) LONG COMPLEX
1822
1823 void genie_cos_double_compl (NODE_T * p)
1824 {
1825 CD_C_FUNCTION (p, ccos_double);
1826 }
1827
1828 //! @brief PROC long ctan = (LONG COMPLEX) LONG COMPLEX
1829
1830 void genie_tan_double_compl (NODE_T * p)
1831 {
1832 CD_C_FUNCTION (p, ctan_double);
1833 }
1834
1835 //! @brief PROC long casin = (LONG COMPLEX) LONG COMPLEX
1836
1837 void genie_asin_double_compl (NODE_T * p)
1838 {
1839 CD_C_FUNCTION (p, casin_double);
1840 }
1841
1842 //! @brief PROC long cacos = (LONG COMPLEX) LONG COMPLEX
1843
1844 void genie_acos_double_compl (NODE_T * p)
1845 {
1846 CD_C_FUNCTION (p, cacos_double);
1847 }
1848
1849 //! @brief PROC long catan = (LONG COMPLEX) LONG COMPLEX
1850
1851 void genie_atan_double_compl (NODE_T * p)
1852 {
1853 CD_C_FUNCTION (p, catan_double);
1854 }
1855
1856 //! @brief PROC long cexp = (LONG COMPLEX) LONG COMPLEX
1857
1858 void genie_exp_double_compl (NODE_T * p)
1859 {
1860 CD_C_FUNCTION (p, cexp_double);
1861 }
1862
1863 //! @brief PROC long cln = (LONG COMPLEX) LONG COMPLEX
1864
1865 void genie_ln_double_compl (NODE_T * p)
1866 {
1867 CD_C_FUNCTION (p, clog_double);
1868 }
1869
1870 //! @brief PROC long csinh = (LONG COMPLEX) LONG COMPLEX
1871
1872 void genie_sinh_double_compl (NODE_T * p)
1873 {
1874 CD_C_FUNCTION (p, csinh_double);
1875 }
1876
1877 //! @brief PROC long ccosh = (LONG COMPLEX) LONG COMPLEX
1878
1879 void genie_cosh_double_compl (NODE_T * p)
1880 {
1881 CD_C_FUNCTION (p, ccosh_double);
1882 }
1883
1884 //! @brief PROC long ctanh = (LONG COMPLEX) LONG COMPLEX
1885
1886 void genie_tanh_double_compl (NODE_T * p)
1887 {
1888 CD_C_FUNCTION (p, ctanh_double);
1889 }
1890
1891 //! @brief PROC long casinh = (LONG COMPLEX) LONG COMPLEX
1892
1893 void genie_asinh_double_compl (NODE_T * p)
1894 {
1895 CD_C_FUNCTION (p, casinh_double);
1896 }
1897
1898 //! @brief PROC long cacosh = (LONG COMPLEX) LONG COMPLEX
1899
1900 void genie_acosh_double_compl (NODE_T * p)
1901 {
1902 CD_C_FUNCTION (p, cacosh_double);
1903 }
1904
1905 //! @brief PROC long catanh = (LONG COMPLEX) LONG COMPLEX
1906
1907 void genie_atanh_double_compl (NODE_T * p)
1908 {
1909 CD_C_FUNCTION (p, catanh_double);
1910 }
1911
1912 //! @brief PROC next long random = LONG REAL
1913
1914 void genie_next_random_double (NODE_T * p)
1915 {
1916 // This is 'real width' digits only.
1917 genie_next_random (p);
1918 genie_lengthen_real_to_double (p);
1919 }
1920
1921 #define CALL(g, x, y) {\
1922 ADDR_T pop_sp = A68G_SP;\
1923 A68G_LONG_REAL *z = (A68G_LONG_REAL *) STACK_TOP;\
1924 DOUBLE_NUM_T _w_;\
1925 _w_.f = (x);\
1926 PUSH_VALUE (_p_, _w_, A68G_LONG_REAL);\
1927 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);\
1928 (y) = VALUE (z).f;\
1929 A68G_SP = pop_sp;\
1930 }
1931
1932 //! @brief Transform string into real-16.
1933
1934 DOUBLE_T string_to_double (char *s, char **end)
1935 {
1936 errno = 0;
1937 DOUBLE_T y[A68G_DOUBLE_DIG];
1938 for (int i = 0; i < A68G_DOUBLE_DIG; i++) {
1939 y[i] = 0.0q;
1940 }
1941 if (end != NO_REF) {
1942 (*end) = &(s[0]);
1943 }
1944 while (IS_SPACE (s[0])) {
1945 s++;
1946 }
1947 // Scan mantissa digits and put them into "y".
1948 DOUBLE_T W;
1949 if (s[0] == '-') {
1950 W = -1.0q;
1951 } else {
1952 W = 1.0q;
1953 }
1954 if (s[0] == '+' || s[0] == '-') {
1955 s++;
1956 }
1957 while (s[0] == '0') {
1958 s++;
1959 }
1960 int dot = -1, pos = 0, pow = 0;
1961 while (pow < A68G_DOUBLE_DIG && s[pos] != NULL_CHAR && (IS_DIGIT (s[pos]) || s[pos] == POINT_CHAR)) {
1962 if (s[pos] == POINT_CHAR) {
1963 dot = pos;
1964 } else {
1965 int val = (int) s[pos] - (int) '0';
1966 y[pow] = W * val;
1967 W /= 10.0q;
1968 pow++;
1969 }
1970 pos++;
1971 }
1972 while (IS_DIGIT (s[pos])) {
1973 pos++;
1974 }
1975 if (end != NO_REF) {
1976 (*end) = &(s[pos]);
1977 }
1978 // Sum from low to high to preserve precision.
1979 DOUBLE_T sum = 0.0q;
1980 for (int i = A68G_DOUBLE_DIG - 1; i >= 0; i--) {
1981 sum = sum + y[i];
1982 }
1983 // See if there is an exponent.
1984 int expo;
1985 if (s[pos] != NULL_CHAR && TO_UPPER (s[pos]) == TO_UPPER (EXPONENT_CHAR)) {
1986 expo = (int) strtol (&(s[++pos]), end, 10);
1987 } else {
1988 expo = 0;
1989 }
1990 // Standardise.
1991 if (dot >= 0) {
1992 expo += dot - 1;
1993 } else {
1994 expo += pow - 1;
1995 }
1996 while (sum != 0.0q && fabs_double (sum) < 1.0q) {
1997 sum *= 10.0q;
1998 expo -= 1;
1999 }
2000 if (errno == 0) {
2001 return sum * ten_up_double (expo);
2002 } else {
2003 return 0.0q;
2004 }
2005 }
2006
2007 void genie_beta_inc_cf_double (NODE_T * p)
2008 {
2009 A68G_LONG_REAL x, s, t;
2010 POP_OBJECT (p, &x, A68G_LONG_REAL);
2011 POP_OBJECT (p, &t, A68G_LONG_REAL);
2012 POP_OBJECT (p, &s, A68G_LONG_REAL);
2013 errno = 0;
2014 PUSH_VALUE (p, dble (a68g_beta_inc_double (VALUE (&s).f, VALUE (&t).f, VALUE (&x).f)), A68G_LONG_REAL);
2015 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
2016 }
2017
2018 void genie_beta_double (NODE_T * p)
2019 {
2020 A68G_LONG_REAL a, b;
2021 POP_OBJECT (p, &b, A68G_LONG_REAL);
2022 POP_OBJECT (p, &a, A68G_LONG_REAL);
2023 errno = 0;
2024 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);
2025 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
2026 }
2027
2028 void genie_ln_beta_double (NODE_T * p)
2029 {
2030 A68G_LONG_REAL a, b;
2031 POP_OBJECT (p, &b, A68G_LONG_REAL);
2032 POP_OBJECT (p, &a, A68G_LONG_REAL);
2033 errno = 0;
2034 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);
2035 MATH_RTE (p, errno != 0, M_LONG_REAL, NO_TEXT);
2036 }
2037
2038 // LONG REAL infinity
2039
2040 void genie_infinity_double (NODE_T * p)
2041 {
2042 PUSH_VALUE (p, dble (A68G_POSINF_DOUBLE), A68G_LONG_REAL);
2043 }
2044
2045 // LONG REAL minus infinity
2046
2047 void genie_minus_infinity_double (NODE_T * p)
2048 {
2049 PUSH_VALUE (p, dble (A68G_MININF_DOUBLE), A68G_LONG_REAL);
2050 }
2051
2052 // Range check.
2053
2054 BOOL_T a68g_finite_double (REAL_T x)
2055 {
2056 return !isinfq (x) && !isnanq (x);
2057 }
2058
2059 // Range check.
2060
2061 BOOL_T a68g_isnan_double (REAL_T x)
2062 {
2063 return isnanq (x);
2064 }
2065
2066 // Range check.
2067
2068 BOOL_T a68g_isinf_double (REAL_T x)
2069 {
2070 return isinfq (x);
2071 }
2072
2073 #endif
|
© 2002-2026 J.M. van der Veer (jmvdveer@xs4all.nl)
|