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


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