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


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)