single.c

     
   1  //! @file single.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   6  //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
   7  //!
   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  //! INT, REAL, COMPLEX and BITS routines.
  25  
  26  #include "a68g.h"
  27  #include "a68g-genie.h"
  28  #include "a68g-prelude.h"
  29  #include "a68g-double.h"
  30  #include "a68g-numbers.h"
  31  #include "a68g-stddef.h"
  32  
  33  // INT operations.
  34  
  35  // OP - = (INT) INT.
  36  
  37  A68_MONAD (genie_minus_int, A68_INT, -);
  38  
  39  // OP ABS = (INT) INT
  40  
  41  void genie_abs_int (NODE_T * p)
  42  {
  43    A68_INT *j;
  44    POP_OPERAND_ADDRESS (p, j, A68_INT);
  45    VALUE (j) = ABS (VALUE (j));
  46  }
  47  
  48  // OP SIGN = (INT) INT
  49  
  50  void genie_sign_int (NODE_T * p)
  51  {
  52    A68_INT *j;
  53    POP_OPERAND_ADDRESS (p, j, A68_INT);
  54    VALUE (j) = SIGN (VALUE (j));
  55  }
  56  
  57  // OP ODD = (INT) BOOL
  58  
  59  void genie_odd_int (NODE_T * p)
  60  {
  61    A68_INT j;
  62    POP_OBJECT (p, &j, A68_INT);
  63    PUSH_VALUE (p, (BOOL_T) ((VALUE (&j) >= 0 ? VALUE (&j) : -VALUE (&j)) % 2 == 1), A68_BOOL);
  64  }
  65  
  66  // OP + = (INT, INT) INT
  67  
  68  void genie_add_int (NODE_T * p)
  69  {
  70    A68_INT *i, *j;
  71    POP_OPERAND_ADDRESSES (p, i, j, A68_INT);
  72    errno = 0;
  73    VALUE (i) = a68_add_int (VALUE (i), VALUE (j));
  74    MATH_RTE (p, errno != 0, M_INT, "M overflow");
  75  }
  76  
  77  // OP - = (INT, INT) INT
  78  
  79  void genie_sub_int (NODE_T * p)
  80  {
  81    A68_INT *i, *j;
  82    POP_OPERAND_ADDRESSES (p, i, j, A68_INT);
  83    errno = 0;
  84    VALUE (i) = a68_sub_int (VALUE (i), VALUE (j));
  85    MATH_RTE (p, errno != 0, M_INT, "M overflow");
  86  }
  87  
  88  // OP * = (INT, INT) INT
  89  
  90  void genie_mul_int (NODE_T * p)
  91  {
  92    A68_INT *i, *j;
  93    POP_OPERAND_ADDRESSES (p, i, j, A68_INT);
  94    errno = 0;
  95    VALUE (i) = a68_mul_int (VALUE (i), VALUE (j));
  96    MATH_RTE (p, errno != 0, M_INT, "M overflow");
  97  }
  98  
  99  // OP OVER = (INT, INT) INT
 100  
 101  void genie_over_int (NODE_T * p)
 102  {
 103    A68_INT *i, *j;
 104    POP_OPERAND_ADDRESSES (p, i, j, A68_INT);
 105    errno = 0;
 106    VALUE (i) = a68_over_int (VALUE (i), VALUE (j));
 107    MATH_RTE (p, errno != 0, M_INT, ERROR_DIVISION_BY_ZERO);
 108  }
 109  
 110  // OP MOD = (INT, INT) INT
 111  
 112  void genie_mod_int (NODE_T * p)
 113  {
 114    A68_INT *i, *j;
 115    POP_OPERAND_ADDRESSES (p, i, j, A68_INT);
 116    errno = 0;
 117    VALUE (i) = a68_mod_int (VALUE (i), VALUE (j));
 118    MATH_RTE (p, errno != 0, M_INT, ERROR_DIVISION_BY_ZERO);
 119  }
 120  
 121  // OP / = (INT, INT) REAL
 122  
 123  void genie_div_int (NODE_T * p)
 124  {
 125    A68_INT i, j;
 126    POP_OBJECT (p, &j, A68_INT);
 127    POP_OBJECT (p, &i, A68_INT);
 128    errno = 0;
 129    PUSH_VALUE (p, a68_div_int (VALUE (&i), VALUE (&j)), A68_REAL);
 130    MATH_RTE (p, errno != 0, M_INT, "M division by zero");
 131  }
 132  
 133  // OP ** = (INT, INT) INT
 134  
 135  void genie_pow_int (NODE_T * p)
 136  {
 137    A68_INT i, j;
 138    POP_OBJECT (p, &j, A68_INT);
 139    PRELUDE_ERROR (VALUE (&j) < 0, p, ERROR_EXPONENT_INVALID, M_INT);
 140    POP_OBJECT (p, &i, A68_INT);
 141    errno = 0;
 142    PUSH_VALUE (p, a68_m_up_n (VALUE (&i), VALUE (&j)), A68_INT);
 143    MATH_RTE (p, errno != 0, M_INT, "M overflow");
 144  }
 145  
 146  // OP (INT, INT) BOOL.
 147  
 148  #define A68_CMP_INT(n, OP)\
 149  void n (NODE_T * p) {\
 150    A68_INT i, j;\
 151    POP_OBJECT (p, &j, A68_INT);\
 152    POP_OBJECT (p, &i, A68_INT);\
 153    PUSH_VALUE (p, (BOOL_T) (VALUE (&i) OP VALUE (&j)), A68_BOOL);\
 154    }
 155  
 156  A68_CMP_INT (genie_eq_int, ==);
 157  A68_CMP_INT (genie_ne_int, !=);
 158  A68_CMP_INT (genie_lt_int, <);
 159  A68_CMP_INT (genie_gt_int, >);
 160  A68_CMP_INT (genie_le_int, <=);
 161  A68_CMP_INT (genie_ge_int, >=);
 162  
 163  // OP +:= = (REF INT, INT) REF INT
 164  
 165  void genie_plusab_int (NODE_T * p)
 166  {
 167    genie_f_and_becomes (p, M_REF_INT, genie_add_int);
 168  }
 169  
 170  // OP -:= = (REF INT, INT) REF INT
 171  
 172  void genie_minusab_int (NODE_T * p)
 173  {
 174    genie_f_and_becomes (p, M_REF_INT, genie_sub_int);
 175  }
 176  
 177  // OP *:= = (REF INT, INT) REF INT
 178  
 179  void genie_timesab_int (NODE_T * p)
 180  {
 181    genie_f_and_becomes (p, M_REF_INT, genie_mul_int);
 182  }
 183  
 184  // OP %:= = (REF INT, INT) REF INT
 185  
 186  void genie_overab_int (NODE_T * p)
 187  {
 188    genie_f_and_becomes (p, M_REF_INT, genie_over_int);
 189  }
 190  
 191  // OP %*:= = (REF INT, INT) REF INT
 192  
 193  void genie_modab_int (NODE_T * p)
 194  {
 195    genie_f_and_becomes (p, M_REF_INT, genie_mod_int);
 196  }
 197  
 198  // REAL operations.
 199  
 200  // OP - = (REAL) REAL.
 201  
 202  A68_MONAD (genie_minus_real, A68_REAL, -);
 203  
 204  // OP ABS = (REAL) REAL
 205  
 206  void genie_abs_real (NODE_T * p)
 207  {
 208    A68_REAL *x;
 209    POP_OPERAND_ADDRESS (p, x, A68_REAL);
 210    VALUE (x) = ABS (VALUE (x));
 211  }
 212  
 213  // OP ROUND = (REAL) INT
 214  
 215  void genie_round_real (NODE_T * p)
 216  {
 217    A68_REAL x;
 218    POP_OBJECT (p, &x, A68_REAL);
 219    PRELUDE_ERROR (VALUE (&x) < -(REAL_T) A68_MAX_INT || VALUE (&x) > (REAL_T) A68_MAX_INT, p, ERROR_OUT_OF_BOUNDS, M_INT);
 220    PUSH_VALUE (p, a68_round (VALUE (&x)), A68_INT);
 221  }
 222  
 223  // OP ENTIER = (REAL) INT
 224  
 225  void genie_entier_real (NODE_T * p)
 226  {
 227    A68_REAL x;
 228    POP_OBJECT (p, &x, A68_REAL);
 229    PRELUDE_ERROR (VALUE (&x) < -(REAL_T) A68_MAX_INT || VALUE (&x) > (REAL_T) A68_MAX_INT, p, ERROR_OUT_OF_BOUNDS, M_INT);
 230    PUSH_VALUE (p, (INT_T) floor (VALUE (&x)), A68_INT);
 231  }
 232  
 233  // OP SIGN = (REAL) INT
 234  
 235  void genie_sign_real (NODE_T * p)
 236  {
 237    A68_REAL x;
 238    POP_OBJECT (p, &x, A68_REAL);
 239    PUSH_VALUE (p, SIGN (VALUE (&x)), A68_INT);
 240  }
 241  
 242  // OP + = (REAL, REAL) REAL
 243  
 244  void genie_add_real (NODE_T * p)
 245  {
 246    A68_REAL *x, *y;
 247    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 248    VALUE (x) += VALUE (y);
 249    CHECK_REAL (p, VALUE (x));
 250  }
 251  
 252  // OP - = (REAL, REAL) REAL
 253  
 254  void genie_sub_real (NODE_T * p)
 255  {
 256    A68_REAL *x, *y;
 257    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 258    VALUE (x) -= VALUE (y);
 259    CHECK_REAL (p, VALUE (x));
 260  }
 261  
 262  // OP * = (REAL, REAL) REAL
 263  
 264  void genie_mul_real (NODE_T * p)
 265  {
 266    A68_REAL *x, *y;
 267    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 268    VALUE (x) *= VALUE (y);
 269    CHECK_REAL (p, VALUE (x));
 270  }
 271  
 272  // OP / = (REAL, REAL) REAL
 273  
 274  void genie_div_real (NODE_T * p)
 275  {
 276    A68_REAL *x, *y;
 277    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 278    PRELUDE_ERROR (VALUE (y) == 0.0, p, ERROR_DIVISION_BY_ZERO, M_REAL);
 279    VALUE (x) /= VALUE (y);
 280  }
 281  
 282  // OP ** = (REAL, INT) REAL
 283  
 284  void genie_pow_real_int (NODE_T * p)
 285  {
 286    A68_INT j;
 287    A68_REAL x;
 288    POP_OBJECT (p, &j, A68_INT);
 289    POP_OBJECT (p, &x, A68_REAL);
 290    REAL_T z = a68_x_up_n_real (VALUE (&x), VALUE (&j));
 291    CHECK_REAL (p, z);
 292    PUSH_VALUE (p, z, A68_REAL);
 293  }
 294  
 295  // OP ** = (REAL, REAL) REAL
 296  
 297  void genie_pow_real (NODE_T * p)
 298  {
 299    A68_REAL x, y;
 300    POP_OBJECT (p, &y, A68_REAL);
 301    POP_OBJECT (p, &x, A68_REAL);
 302    errno = 0;
 303    REAL_T z = a68_x_up_y (VALUE (&x), VALUE (&y));
 304    MATH_RTE (p, errno != 0, M_REAL, NO_TEXT);
 305    PUSH_VALUE (p, z, A68_REAL);
 306  }
 307  
 308  // OP (REAL, REAL) BOOL.
 309  
 310  #define A68_CMP_REAL(n, OP)\
 311  void n (NODE_T * p) {\
 312    A68_REAL i, j;\
 313    POP_OBJECT (p, &j, A68_REAL);\
 314    POP_OBJECT (p, &i, A68_REAL);\
 315    PUSH_VALUE (p, (BOOL_T) (VALUE (&i) OP VALUE (&j)), A68_BOOL);\
 316    }
 317  
 318  A68_CMP_REAL (genie_eq_real, ==);
 319  A68_CMP_REAL (genie_ne_real, !=);
 320  A68_CMP_REAL (genie_lt_real, <);
 321  A68_CMP_REAL (genie_gt_real, >);
 322  A68_CMP_REAL (genie_le_real, <=);
 323  A68_CMP_REAL (genie_ge_real, >=);
 324  
 325  // OP +:= = (REF REAL, REAL) REF REAL
 326  
 327  void genie_plusab_real (NODE_T * p)
 328  {
 329    genie_f_and_becomes (p, M_REF_REAL, genie_add_real);
 330  }
 331  
 332  // OP -:= = (REF REAL, REAL) REF REAL
 333  
 334  void genie_minusab_real (NODE_T * p)
 335  {
 336    genie_f_and_becomes (p, M_REF_REAL, genie_sub_real);
 337  }
 338  
 339  // OP *:= = (REF REAL, REAL) REF REAL
 340  
 341  void genie_timesab_real (NODE_T * p)
 342  {
 343    genie_f_and_becomes (p, M_REF_REAL, genie_mul_real);
 344  }
 345  
 346  // OP /:= = (REF REAL, REAL) REF REAL
 347  
 348  void genie_divab_real (NODE_T * p)
 349  {
 350    genie_f_and_becomes (p, M_REF_REAL, genie_div_real);
 351  }
 352  
 353  // @brief PROC (INT) VOID first random
 354  
 355  void genie_first_random (NODE_T * p)
 356  {
 357    A68_INT i;
 358    POP_OBJECT (p, &i, A68_INT);
 359    init_rng ((unt) VALUE (&i));
 360  }
 361  
 362  // @brief PROC REAL next random
 363  
 364  void genie_next_random (NODE_T * p)
 365  {
 366    PUSH_VALUE (p, a68_unif_rand (), A68_REAL);
 367  }
 368  
 369  // @brief PROC REAL rnd
 370  
 371  void genie_next_rnd (NODE_T * p)
 372  {
 373    PUSH_VALUE (p, 2 * a68_unif_rand () - 1, A68_REAL);
 374  }
 375  
 376  // @brief PROC (REAL) REAL sqrt
 377  
 378  void genie_sqrt_real (NODE_T * p)
 379  {
 380    C_FUNCTION (p, sqrt);
 381  }
 382  
 383  // @brief PROC (REAL) REAL curt
 384  
 385  void genie_curt_real (NODE_T * p)
 386  {
 387    C_FUNCTION (p, cbrt);
 388  }
 389  
 390  // @brief PROC (REAL) REAL exp
 391  
 392  void genie_exp_real (NODE_T * p)
 393  {
 394    A68_REAL *x;
 395    POP_OPERAND_ADDRESS (p, x, A68_REAL);
 396    errno = 0;
 397    VALUE (x) = exp (VALUE (x));
 398    MATH_RTE (p, errno != 0, M_REAL, NO_TEXT);
 399  }
 400  
 401  // @brief PROC (REAL) REAL ln
 402  
 403  void genie_ln_real (NODE_T * p)
 404  {
 405    C_FUNCTION (p, a68_ln_real);
 406  }
 407  
 408  // @brief PROC (REAL) REAL ln1p
 409  
 410  void genie_ln1p_real (NODE_T * p)
 411  {
 412    C_FUNCTION (p, a68_ln1p_real);
 413  }
 414  
 415  // @brief PROC (REAL) REAL log
 416  
 417  void genie_log_real (NODE_T * p)
 418  {
 419    C_FUNCTION (p, log10);
 420  }
 421  
 422  // @brief PROC (REAL) REAL sin
 423  
 424  void genie_sin_real (NODE_T * p)
 425  {
 426    C_FUNCTION (p, sin);
 427  }
 428  
 429  // @brief PROC (REAL) REAL arcsin
 430  
 431  void genie_asin_real (NODE_T * p)
 432  {
 433    C_FUNCTION (p, asin);
 434  }
 435  
 436  // @brief PROC (REAL) REAL cas
 437  
 438  void genie_cas_real (NODE_T * p)
 439  {
 440    C_FUNCTION (p, a68_cas_real);
 441  }
 442  
 443  // @brief PROC (REAL) REAL cos
 444  
 445  void genie_cos_real (NODE_T * p)
 446  {
 447    C_FUNCTION (p, cos);
 448  }
 449  
 450  // @brief PROC (REAL) REAL arccos
 451  
 452  void genie_acos_real (NODE_T * p)
 453  {
 454    C_FUNCTION (p, acos);
 455  }
 456  
 457  // @brief PROC (REAL) REAL tan
 458  
 459  void genie_tan_real (NODE_T * p)
 460  {
 461    C_FUNCTION (p, tan);
 462  }
 463  
 464  // @brief PROC (REAL) REAL csc 
 465  
 466  void genie_csc_real (NODE_T * p)
 467  {
 468    C_FUNCTION (p, a68_csc_real);
 469  }
 470  
 471  // @brief PROC (REAL) REAL acsc
 472  
 473  void genie_acsc_real (NODE_T * p)
 474  {
 475    C_FUNCTION (p, a68_acsc_real);
 476  }
 477  
 478  // @brief PROC (REAL) REAL sec 
 479  
 480  void genie_sec_real (NODE_T * p)
 481  {
 482    C_FUNCTION (p, a68_sec_real);
 483  }
 484  
 485  // @brief PROC (REAL) REAL asec
 486  
 487  void genie_asec_real (NODE_T * p)
 488  {
 489    C_FUNCTION (p, a68_asec_real);
 490  }
 491  
 492  // @brief PROC (REAL) REAL cot 
 493  
 494  void genie_cot_real (NODE_T * p)
 495  {
 496    C_FUNCTION (p, a68_cot_real);
 497  }
 498  
 499  // @brief PROC (REAL) REAL acot
 500  
 501  void genie_acot_real (NODE_T * p)
 502  {
 503    C_FUNCTION (p, a68_acot_real);
 504  }
 505  
 506  // @brief PROC (REAL) REAL arctan
 507  
 508  void genie_atan_real (NODE_T * p)
 509  {
 510    C_FUNCTION (p, atan);
 511  }
 512  
 513  // @brief PROC (REAL, REAL) REAL arctan2
 514  
 515  void genie_atan2_real (NODE_T * p)
 516  {
 517    A68_REAL *x, *y;
 518    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 519    errno = 0;
 520    PRELUDE_ERROR (VALUE (x) == 0.0 && VALUE (y) == 0.0, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
 521    VALUE (x) = a68_atan2_real (VALUE (y), VALUE (x));
 522    PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 523  }
 524  
 525  // @brief PROC (REAL) REAL sindg
 526  
 527  void genie_sindg_real (NODE_T * p)
 528  {
 529    C_FUNCTION (p, a68_sindg_real);
 530  }
 531  
 532  // @brief PROC (REAL) REAL arcsindg
 533  
 534  void genie_asindg_real (NODE_T * p)
 535  {
 536    C_FUNCTION (p, a68_asindg_real);
 537  }
 538  
 539  // @brief PROC (REAL) REAL cosdg
 540  
 541  void genie_cosdg_real (NODE_T * p)
 542  {
 543    C_FUNCTION (p, a68_cosdg_real);
 544  }
 545  
 546  // @brief PROC (REAL) REAL arccosdg
 547  
 548  void genie_acosdg_real (NODE_T * p)
 549  {
 550    C_FUNCTION (p, a68_acosdg_real);
 551  }
 552  
 553  // @brief PROC (REAL) REAL tandg
 554  
 555  void genie_tandg_real (NODE_T * p)
 556  {
 557    C_FUNCTION (p, a68_tandg_real);
 558  }
 559  
 560  // @brief PROC (REAL) REAL arctandg
 561  
 562  void genie_atandg_real (NODE_T * p)
 563  {
 564    C_FUNCTION (p, a68_atandg_real);
 565  }
 566  
 567  // @brief PROC (REAL) REAL cscdg
 568  
 569  void genie_cscdg_real (NODE_T * p)
 570  {
 571    C_FUNCTION (p, a68_cscdg_real);
 572  }
 573  
 574  // @brief PROC (REAL) REAL acscdg
 575  
 576  void genie_acscdg_real (NODE_T * p)
 577  {
 578    C_FUNCTION (p, a68_acscdg_real);
 579  }
 580  
 581  // @brief PROC (REAL) REAL secdg 
 582  
 583  void genie_secdg_real (NODE_T * p)
 584  {
 585    C_FUNCTION (p, a68_secdg_real);
 586  }
 587  
 588  // @brief PROC (REAL) REAL asecdg
 589  
 590  void genie_asecdg_real (NODE_T * p)
 591  {
 592    C_FUNCTION (p, a68_asecdg_real);
 593  }
 594  
 595  // @brief PROC (REAL) REAL cotdg 
 596  
 597  void genie_cotdg_real (NODE_T * p)
 598  {
 599    C_FUNCTION (p, a68_cot_realdg_real);
 600  }
 601  
 602  // @brief PROC (REAL) REAL acotdg
 603  
 604  void genie_acotdg_real (NODE_T * p)
 605  {
 606    C_FUNCTION (p, a68_acotdg_real);
 607  }
 608  
 609  // @brief PROC (REAL, REAL) REAL arctan2dg
 610  
 611  void genie_atan2dg_real (NODE_T * p)
 612  {
 613    A68_REAL *x, *y;
 614    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 615    errno = 0;
 616    PRELUDE_ERROR (VALUE (x) == 0.0 && VALUE (y) == 0.0, p, ERROR_INVALID_ARGUMENT, M_LONG_REAL);
 617    VALUE (x) = CONST_180_OVER_PI * a68_atan2_real (VALUE (y), VALUE (x));
 618    PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 619  }
 620  
 621  // @brief PROC (REAL) REAL sinpi
 622  
 623  void genie_sinpi_real (NODE_T * p)
 624  {
 625    C_FUNCTION (p, a68_sinpi_real);
 626  }
 627  
 628  // @brief PROC (REAL) REAL cospi
 629  
 630  void genie_cospi_real (NODE_T * p)
 631  {
 632    C_FUNCTION (p, a68_cospi_real);
 633  }
 634  
 635  // @brief PROC (REAL) REAL tanpi
 636  
 637  void genie_tanpi_real (NODE_T * p)
 638  {
 639    C_FUNCTION (p, a68_tanpi_real);
 640  }
 641  
 642  // @brief PROC (REAL) REAL cotpi 
 643  
 644  void genie_cotpi_real (NODE_T * p)
 645  {
 646    C_FUNCTION (p, a68_cot_realpi);
 647  }
 648  
 649  // @brief PROC (REAL) REAL sinh
 650  
 651  void genie_sinh_real (NODE_T * p)
 652  {
 653    C_FUNCTION (p, sinh);
 654  }
 655  
 656  // @brief PROC (REAL) REAL cosh
 657  
 658  void genie_cosh_real (NODE_T * p)
 659  {
 660    C_FUNCTION (p, cosh);
 661  }
 662  
 663  // @brief PROC (REAL) REAL tanh
 664  
 665  void genie_tanh_real (NODE_T * p)
 666  {
 667    C_FUNCTION (p, tanh);
 668  }
 669  
 670  // @brief PROC (REAL) REAL asinh
 671  
 672  void genie_asinh_real (NODE_T * p)
 673  {
 674    C_FUNCTION (p, a68_asinh_real);
 675  }
 676  
 677  // @brief PROC (REAL) REAL acosh
 678  
 679  void genie_acosh_real (NODE_T * p)
 680  {
 681    C_FUNCTION (p, a68_acosh_real);
 682  }
 683  
 684  // @brief PROC (REAL) REAL atanh
 685  
 686  void genie_atanh_real (NODE_T * p)
 687  {
 688    C_FUNCTION (p, a68_atanh_real);
 689  }
 690  
 691  // @brief PROC (REAL) REAL erf
 692  
 693  void genie_erf_real (NODE_T * p)
 694  {
 695    C_FUNCTION (p, erf);
 696  }
 697  
 698  // @brief PROC (REAL) REAL inverf
 699  
 700  void genie_inverf_real (NODE_T * p)
 701  {
 702    C_FUNCTION (p, a68_inverf_real);
 703  }
 704  
 705  // @brief PROC (REAL) REAL erfc
 706  
 707  void genie_erfc_real (NODE_T * p)
 708  {
 709    C_FUNCTION (p, erfc);
 710  }
 711  
 712  // @brief PROC (REAL) REAL inverfc
 713  
 714  void genie_inverfc_real (NODE_T * p)
 715  {
 716    C_FUNCTION (p, a68_inverfc_real);
 717  }
 718  
 719  // @brief PROC (REAL) REAL gamma
 720  
 721  void genie_gamma_real (NODE_T * p)
 722  {
 723    C_FUNCTION (p, tgamma);
 724  }
 725  
 726  // @brief PROC (REAL) REAL ln gamma
 727  
 728  void genie_ln_gamma_real (NODE_T * p)
 729  {
 730    C_FUNCTION (p, lgamma);
 731  }
 732  
 733  // @brief PROC (REAL, REAL) REAL beta
 734  
 735  void genie_beta_real (NODE_T * p)
 736  {
 737    A68_REAL *x, *y;
 738    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 739    errno = 0;
 740    VALUE (x) = a68_beta_real (VALUE (x), VALUE (y));
 741    PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 742  }
 743  
 744  // @brief PROC (REAL, REAL) REAL ln beta
 745  
 746  void genie_ln_beta_real (NODE_T * p)
 747  {
 748    A68_REAL *x, *y;
 749    POP_OPERAND_ADDRESSES (p, x, y, A68_REAL);
 750    errno = 0;
 751    VALUE (x) = a68_ln_beta_real (VALUE (x), VALUE (y));
 752    PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 753  }
 754  
 755  // @brief PROC (REAL, REAL, REAL) REAL cf beta inc
 756  
 757  void genie_beta_inc_cf_real (NODE_T * p)
 758  {
 759    A68_REAL *s, *t, *x;
 760    POP_3_OPERAND_ADDRESSES (p, s, t, x, A68_REAL);
 761    errno = 0;
 762    VALUE (s) = a68_beta_inc_real (VALUE (s), VALUE (t), VALUE (x));
 763    PRELUDE_ERROR (errno != 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 764  }
 765  
 766  // @brief PROC (REAL, REAL, REAL) REAL lj e 12 6
 767  
 768  void genie_lj_e_12_6 (NODE_T * p)
 769  {
 770    A68_REAL *e, *s, *r;
 771    POP_3_OPERAND_ADDRESSES (p, e, s, r, A68_REAL);
 772    PRELUDE_ERROR (VALUE (r) == 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 773    REAL_T u = (VALUE (s) / VALUE (r));
 774    REAL_T u2 = u * u;
 775    REAL_T u6 = u2 * u2 * u2;
 776    VALUE (e) = 4.0 * VALUE (e) * u6 * (u6 - 1.0);
 777  }
 778  
 779  // @brief PROC (REAL, REAL, REAL) REAL lj f 12 6
 780  
 781  void genie_lj_f_12_6 (NODE_T * p)
 782  {
 783    A68_REAL *e, *s, *r;
 784    POP_3_OPERAND_ADDRESSES (p, e, s, r, A68_REAL);
 785    PRELUDE_ERROR (VALUE (r) == 0, p, ERROR_MATH_EXCEPTION, NO_TEXT);
 786    REAL_T u = (VALUE (s) / VALUE (r));
 787    REAL_T u2 = u * u;
 788    REAL_T u6 = u2 * u2 * u2;
 789    VALUE (e) = 24.0 * VALUE (e) * u * u6 * (1.0 - 2.0 * u6);
 790  }
 791  
 792  // This file also contains Algol68G's standard environ for complex numbers.
 793  // Some of the LONG operations are generic for LONG and LONG LONG.
 794  // 
 795  // Some routines are based on
 796  //   GNU Scientific Library
 797  //   Abramowitz and Stegun.
 798  
 799  // OP +* = (REAL, REAL) COMPLEX
 800  
 801  void genie_i_complex (NODE_T * p)
 802  {
 803  // This function must exist so the code generator recognises it!
 804    (void) p;
 805  }
 806  
 807  // OP +* = (INT, INT) COMPLEX
 808  
 809  void genie_i_int_complex (NODE_T * p)
 810  {
 811    A68_INT re, im;
 812    POP_OBJECT (p, &im, A68_INT);
 813    POP_OBJECT (p, &re, A68_INT);
 814    PUSH_VALUE (p, (REAL_T) VALUE (&re), A68_REAL);
 815    PUSH_VALUE (p, (REAL_T) VALUE (&im), A68_REAL);
 816  }
 817  
 818  // OP RE = (COMPLEX) REAL
 819  
 820  void genie_re_complex (NODE_T * p)
 821  {
 822    DECREMENT_STACK_POINTER (p, SIZE (M_REAL));
 823  }
 824  
 825  // OP IM = (COMPLEX) REAL
 826  
 827  void genie_im_complex (NODE_T * p)
 828  {
 829    A68_REAL im;
 830    POP_OBJECT (p, &im, A68_REAL);
 831    *(A68_REAL *) (STACK_OFFSET (-SIZE (M_REAL))) = im;
 832  }
 833  
 834  // OP - = (COMPLEX) COMPLEX
 835  
 836  void genie_minus_complex (NODE_T * p)
 837  {
 838    A68_REAL *re_x, *im_x;
 839    im_x = (A68_REAL *) (STACK_OFFSET (-SIZE (M_REAL)));
 840    re_x = (A68_REAL *) (STACK_OFFSET (-2 * SIZE (M_REAL)));
 841    VALUE (im_x) = -VALUE (im_x);
 842    VALUE (re_x) = -VALUE (re_x);
 843    (void) p;
 844  }
 845  
 846  // ABS = (COMPLEX) REAL
 847  
 848  void genie_abs_complex (NODE_T * p)
 849  {
 850    A68_REAL re_x, im_x;
 851    POP_COMPLEX (p, &re_x, &im_x);
 852    PUSH_VALUE (p, a68_hypot_real (VALUE (&re_x), VALUE (&im_x)), A68_REAL);
 853  }
 854  
 855  // OP ARG = (COMPLEX) REAL
 856  
 857  void genie_arg_complex (NODE_T * p)
 858  {
 859    A68_REAL re_x, im_x;
 860    POP_COMPLEX (p, &re_x, &im_x);
 861    PRELUDE_ERROR (VALUE (&re_x) == 0.0 && VALUE (&im_x) == 0.0, p, ERROR_INVALID_ARGUMENT, M_COMPLEX);
 862    PUSH_VALUE (p, atan2 (VALUE (&im_x), VALUE (&re_x)), A68_REAL);
 863  }
 864  
 865  // OP CONJ = (COMPLEX) COMPLEX
 866  
 867  void genie_conj_complex (NODE_T * p)
 868  {
 869    A68_REAL *im;
 870    POP_OPERAND_ADDRESS (p, im, A68_REAL);
 871    VALUE (im) = -VALUE (im);
 872  }
 873  
 874  // OP + = (COMPLEX, COMPLEX) COMPLEX
 875  
 876  void genie_add_complex (NODE_T * p)
 877  {
 878    A68_REAL *re_x, *im_x, re_y, im_y;
 879    POP_COMPLEX (p, &re_y, &im_y);
 880    im_x = (A68_REAL *) (STACK_OFFSET (-SIZE (M_REAL)));
 881    re_x = (A68_REAL *) (STACK_OFFSET (-2 * SIZE (M_REAL)));
 882    VALUE (im_x) += VALUE (&im_y);
 883    VALUE (re_x) += VALUE (&re_y);
 884    CHECK_COMPLEX (p, VALUE (re_x), VALUE (im_x));
 885  }
 886  
 887  // OP - = (COMPLEX, COMPLEX) COMPLEX
 888  
 889  void genie_sub_complex (NODE_T * p)
 890  {
 891    A68_REAL *re_x, *im_x, re_y, im_y;
 892    POP_COMPLEX (p, &re_y, &im_y);
 893    im_x = (A68_REAL *) (STACK_OFFSET (-SIZE (M_REAL)));
 894    re_x = (A68_REAL *) (STACK_OFFSET (-2 * SIZE (M_REAL)));
 895    VALUE (im_x) -= VALUE (&im_y);
 896    VALUE (re_x) -= VALUE (&re_y);
 897    CHECK_COMPLEX (p, VALUE (re_x), VALUE (im_x));
 898  }
 899  
 900  // OP * = (COMPLEX, COMPLEX) COMPLEX
 901  
 902  void genie_mul_complex (NODE_T * p)
 903  {
 904    A68_REAL re_x, im_x, re_y, im_y;
 905    POP_COMPLEX (p, &re_y, &im_y);
 906    POP_COMPLEX (p, &re_x, &im_x);
 907    REAL_T re = VALUE (&re_x) * VALUE (&re_y) - VALUE (&im_x) * VALUE (&im_y);
 908    REAL_T im = VALUE (&im_x) * VALUE (&re_y) + VALUE (&re_x) * VALUE (&im_y);
 909    CHECK_COMPLEX (p, re, im);
 910    PUSH_COMPLEX (p, re, im);
 911  }
 912  
 913  // OP / = (COMPLEX, COMPLEX) COMPLEX
 914  
 915  void genie_div_complex (NODE_T * p)
 916  {
 917    A68_REAL re_x, im_x, re_y, im_y;
 918    REAL_T re = 0.0, im = 0.0;
 919    POP_COMPLEX (p, &re_y, &im_y);
 920    POP_COMPLEX (p, &re_x, &im_x);
 921  #if !defined (HAVE_IEEE_754)
 922    PRELUDE_ERROR (VALUE (&re_y) == 0.0 && VALUE (&im_y) == 0.0, p, ERROR_DIVISION_BY_ZERO, M_COMPLEX);
 923  #endif
 924    if (ABS (VALUE (&re_y)) >= ABS (VALUE (&im_y))) {
 925      REAL_T r = VALUE (&im_y) / VALUE (&re_y), den = VALUE (&re_y) + r * VALUE (&im_y);
 926      re = (VALUE (&re_x) + r * VALUE (&im_x)) / den;
 927      im = (VALUE (&im_x) - r * VALUE (&re_x)) / den;
 928    } else {
 929      REAL_T r = VALUE (&re_y) / VALUE (&im_y), den = VALUE (&im_y) + r * VALUE (&re_y);
 930      re = (VALUE (&re_x) * r + VALUE (&im_x)) / den;
 931      im = (VALUE (&im_x) * r - VALUE (&re_x)) / den;
 932    }
 933    CHECK_COMPLEX (p, re, im);
 934    PUSH_COMPLEX (p, re, im);
 935  }
 936  
 937  // OP ** = (COMPLEX, INT) COMPLEX
 938  
 939  void genie_pow_complex_int (NODE_T * p)
 940  {
 941    A68_INT j;
 942    POP_OBJECT (p, &j, A68_INT);
 943    A68_REAL re_x, im_x;
 944    POP_COMPLEX (p, &re_x, &im_x);
 945    REAL_T re_z = 1.0, im_z = 0.0;
 946    REAL_T re_y = VALUE (&re_x), im_y = VALUE (&im_x);
 947    INT_T expo = 1;
 948    BOOL_T neg = (BOOL_T) (VALUE (&j) < 0);
 949    if (neg) {
 950      VALUE (&j) = -VALUE (&j);
 951    }
 952    while ((UNSIGNED_T) expo <= (UNSIGNED_T) (VALUE (&j))) {
 953      REAL_T rea;
 954      if (expo & VALUE (&j)) {
 955        rea = re_z * re_y - im_z * im_y;
 956        im_z = re_z * im_y + im_z * re_y;
 957        re_z = rea;
 958      }
 959      rea = re_y * re_y - im_y * im_y;
 960      im_y = im_y * re_y + re_y * im_y;
 961      re_y = rea;
 962      expo <<= 1;
 963    }
 964    CHECK_COMPLEX (p, re_z, im_z);
 965    if (neg) {
 966      PUSH_VALUE (p, 1.0, A68_REAL);
 967      PUSH_VALUE (p, 0.0, A68_REAL);
 968      PUSH_VALUE (p, re_z, A68_REAL);
 969      PUSH_VALUE (p, im_z, A68_REAL);
 970      genie_div_complex (p);
 971    } else {
 972      PUSH_VALUE (p, re_z, A68_REAL);
 973      PUSH_VALUE (p, im_z, A68_REAL);
 974    }
 975  }
 976  
 977  // OP = = (COMPLEX, COMPLEX) BOOL
 978  
 979  void genie_eq_complex (NODE_T * p)
 980  {
 981    A68_REAL re_x, im_x, re_y, im_y;
 982    POP_COMPLEX (p, &re_y, &im_y);
 983    POP_COMPLEX (p, &re_x, &im_x);
 984    PUSH_VALUE (p, (BOOL_T) ((VALUE (&re_x) == VALUE (&re_y)) && (VALUE (&im_x) == VALUE (&im_y))), A68_BOOL);
 985  }
 986  
 987  // OP /= = (COMPLEX, COMPLEX) BOOL
 988  
 989  void genie_ne_complex (NODE_T * p)
 990  {
 991    A68_REAL re_x, im_x, re_y, im_y;
 992    POP_COMPLEX (p, &re_y, &im_y);
 993    POP_COMPLEX (p, &re_x, &im_x);
 994    PUSH_VALUE (p, (BOOL_T) ! ((VALUE (&re_x) == VALUE (&re_y)) && (VALUE (&im_x) == VALUE (&im_y))), A68_BOOL);
 995  }
 996  
 997  // OP +:= = (REF COMPLEX, COMPLEX) REF COMPLEX
 998  
 999  void genie_plusab_complex (NODE_T * p)
1000  {
1001    genie_f_and_becomes (p, M_REF_COMPLEX, genie_add_complex);
1002  }
1003  
1004  // OP -:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1005  
1006  void genie_minusab_complex (NODE_T * p)
1007  {
1008    genie_f_and_becomes (p, M_REF_COMPLEX, genie_sub_complex);
1009  }
1010  
1011  // OP *:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1012  
1013  void genie_timesab_complex (NODE_T * p)
1014  {
1015    genie_f_and_becomes (p, M_REF_COMPLEX, genie_mul_complex);
1016  }
1017  
1018  // OP /:= = (REF COMPLEX, COMPLEX) REF COMPLEX
1019  
1020  void genie_divab_complex (NODE_T * p)
1021  {
1022    genie_f_and_becomes (p, M_REF_COMPLEX, genie_div_complex);
1023  }
1024  
1025  #define C_C_FUNCTION(p, f)\
1026    A68_REAL re, im;\
1027    POP_OBJECT (p, &im, A68_REAL);\
1028    POP_OBJECT (p, &re, A68_REAL);\
1029    errno = 0;\
1030    COMPLEX_T z = VALUE (&re) + VALUE (&im) * _Complex_I;\
1031    z = f (z);\
1032    PUSH_VALUE (p, (REAL_T) creal (z), A68_REAL);\
1033    PUSH_VALUE (p, (REAL_T) cimag (z), A68_REAL);\
1034    MATH_RTE (p, errno != 0, M_COMPLEX, NO_TEXT);
1035  
1036  // @brief PROC (COMPLEX) COMPLEX csqrt
1037  
1038  void genie_sqrt_complex (NODE_T * p)
1039  {
1040    C_C_FUNCTION (p, csqrt);
1041  }
1042  
1043  // @brief PROC (COMPLEX) COMPLEX cexp
1044  
1045  void genie_exp_complex (NODE_T * p)
1046  {
1047    C_C_FUNCTION (p, cexp);
1048  }
1049  
1050  // @brief PROC (COMPLEX) COMPLEX cln
1051  
1052  void genie_ln_complex (NODE_T * p)
1053  {
1054    C_C_FUNCTION (p, clog);
1055  }
1056  
1057  // @brief PROC (COMPLEX) COMPLEX csin
1058  
1059  void genie_sin_complex (NODE_T * p)
1060  {
1061    C_C_FUNCTION (p, csin);
1062  }
1063  
1064  // @brief PROC (COMPLEX) COMPLEX ccos
1065  
1066  void genie_cos_complex (NODE_T * p)
1067  {
1068    C_C_FUNCTION (p, ccos);
1069  }
1070  
1071  // @brief PROC (COMPLEX) COMPLEX ctan
1072  
1073  void genie_tan_complex (NODE_T * p)
1074  {
1075    C_C_FUNCTION (p, ctan);
1076  }
1077  
1078  // @brief PROC carcsin= (COMPLEX) COMPLEX
1079  
1080  void genie_asin_complex (NODE_T * p)
1081  {
1082    C_C_FUNCTION (p, casin);
1083  }
1084  
1085  // @brief PROC (COMPLEX) COMPLEX carccos
1086  
1087  void genie_acos_complex (NODE_T * p)
1088  {
1089    C_C_FUNCTION (p, cacos);
1090  }
1091  
1092  // @brief PROC (COMPLEX) COMPLEX carctan
1093  
1094  void genie_atan_complex (NODE_T * p)
1095  {
1096    C_C_FUNCTION (p, catan);
1097  }
1098  
1099  // @brief PROC (COMPLEX) COMPLEX csinh
1100  
1101  void genie_sinh_complex (NODE_T * p)
1102  {
1103    C_C_FUNCTION (p, csinh);
1104  }
1105  
1106  // @brief PROC (COMPLEX) COMPLEX ccosh
1107  
1108  void genie_cosh_complex (NODE_T * p)
1109  {
1110    C_C_FUNCTION (p, ccosh);
1111  }
1112  
1113  // @brief PROC (COMPLEX) COMPLEX ctanh
1114  
1115  void genie_tanh_complex (NODE_T * p)
1116  {
1117    C_C_FUNCTION (p, ctanh);
1118  }
1119  
1120  // @brief PROC (COMPLEX) COMPLEX carcsinh
1121  
1122  void genie_asinh_complex (NODE_T * p)
1123  {
1124    C_C_FUNCTION (p, casinh);
1125  }
1126  
1127  // @brief PROC (COMPLEX) COMPLEX carccosh
1128  
1129  void genie_acosh_complex (NODE_T * p)
1130  {
1131    C_C_FUNCTION (p, cacosh);
1132  }
1133  
1134  // @brief PROC (COMPLEX) COMPLEX carctanh
1135  
1136  void genie_atanh_complex (NODE_T * p)
1137  {
1138    C_C_FUNCTION (p, catanh);
1139  }
1140  
1141  #define C_C_INLINE(z, x, f)\
1142    COMPLEX_T u = RE (x) + IM (x) * _Complex_I;\
1143    COMPLEX_T v = f (u);\
1144    STATUS_RE (z) = INIT_MASK;\
1145    STATUS_IM (z) = INIT_MASK;\
1146    RE (z) = creal (v);\
1147    IM (z) = cimag (v);\
1148  
1149  //! @brief PROC (COMPLEX) COMPLEX csqrt
1150  
1151  void a68_sqrt_complex (A68_REAL * z, A68_REAL * x)
1152  {
1153    C_C_INLINE (z, x, csqrt);
1154  }
1155  
1156  //! @brief PROC (COMPLEX) COMPLEX cexp
1157  
1158  void a68_exp_real_complex (A68_REAL * z, A68_REAL * x)
1159  {
1160    C_C_INLINE (z, x, cexp);
1161  }
1162  
1163  //! @brief PROC (COMPLEX) COMPLEX cln
1164  
1165  void a68_ln_complex (A68_REAL * z, A68_REAL * x)
1166  {
1167    C_C_INLINE (z, x, clog);
1168  }
1169  
1170  //! @brief PROC (COMPLEX) COMPLEX csin
1171  
1172  void a68_sin_complex (A68_REAL * z, A68_REAL * x)
1173  {
1174    C_C_INLINE (z, x, csin);
1175  }
1176  
1177  //! @brief PROC (COMPLEX) COMPLEX ccos
1178  
1179  void a68_cos_complex (A68_REAL * z, A68_REAL * x)
1180  {
1181    C_C_INLINE (z, x, ccos);
1182  }
1183  
1184  //! @brief PROC (COMPLEX) COMPLEX ctan
1185  
1186  void a68_tan_complex (A68_REAL * z, A68_REAL * x)
1187  {
1188    C_C_INLINE (z, x, ctan);
1189  }
1190  
1191  //! @brief PROC (COMPLEX) COMPLEX casin
1192  
1193  void a68_asin_complex (A68_REAL * z, A68_REAL * x)
1194  {
1195    C_C_INLINE (z, x, casin);
1196  }
1197  
1198  //! @brief PROC (COMPLEX) COMPLEX cacos
1199  
1200  void a68_acos_complex (A68_REAL * z, A68_REAL * x)
1201  {
1202    C_C_INLINE (z, x, cacos);
1203  }
1204  
1205  //! @brief PROC (COMPLEX) COMPLEX catan
1206  
1207  void a68_atan_complex (A68_REAL * z, A68_REAL * x)
1208  {
1209    C_C_INLINE (z, x, catan);
1210  }
1211  
1212  //! @brief PROC (COMPLEX) COMPLEX csinh
1213  
1214  void a68_sinh_complex (A68_REAL * z, A68_REAL * x)
1215  {
1216    C_C_INLINE (z, x, csinh);
1217  }
1218  
1219  //! @brief PROC (COMPLEX) COMPLEX ccosh
1220  
1221  void a68_cosh_complex (A68_REAL * z, A68_REAL * x)
1222  {
1223    C_C_INLINE (z, x, ccosh);
1224  }
1225  
1226  //! @brief PROC (COMPLEX) COMPLEX ctanh
1227  
1228  void a68_tanh_complex (A68_REAL * z, A68_REAL * x)
1229  {
1230    C_C_INLINE (z, x, ctanh);
1231  }
1232  
1233  //! @brief PROC (COMPLEX) COMPLEX casinh
1234  
1235  void a68_asinh_real_complex (A68_REAL * z, A68_REAL * x)
1236  {
1237    C_C_INLINE (z, x, casinh);
1238  }
1239  
1240  //! @brief PROC (COMPLEX) COMPLEX cacosh
1241  
1242  void a68_acosh_real_complex (A68_REAL * z, A68_REAL * x)
1243  {
1244    C_C_INLINE (z, x, cacosh);
1245  }
1246  
1247  //! @brief PROC (COMPLEX) COMPLEX catanh
1248  
1249  void a68_atanh_real_complex (A68_REAL * z, A68_REAL * x)
1250  {
1251    C_C_INLINE (z, x, catanh);
1252  }
1253  
1254  //! @brief PROC (INT, INT) REAL choose
1255  
1256  void genie_fact_real (NODE_T * p)
1257  {
1258    A68_INT n;
1259    POP_OBJECT (p, &n, A68_INT);
1260    errno = 0;
1261    PUSH_VALUE (p, a68_fact_real (VALUE (&n)), A68_REAL);
1262    MATH_RTE (p, errno != 0, M_INT, NO_TEXT);
1263  }
1264  
1265  //! @brief PROC (INT, INT) REAL ln fact
1266  
1267  void genie_ln_fact_real (NODE_T * p)
1268  {
1269    A68_INT n;
1270    POP_OBJECT (p, &n, A68_INT);
1271    errno = 0;
1272    PUSH_VALUE (p, a68_ln_fact_real (VALUE (&n)), A68_REAL);
1273    MATH_RTE (p, errno != 0, M_INT, NO_TEXT);
1274  }
1275  
1276  void genie_choose_real (NODE_T * p)
1277  {
1278    A68_INT n, m;
1279    POP_OBJECT (p, &m, A68_INT);
1280    POP_OBJECT (p, &n, A68_INT);
1281    errno = 0;
1282    PUSH_VALUE (p, a68_choose_real (VALUE (&n), VALUE (&m)), A68_REAL);
1283    MATH_RTE (p, errno != 0, M_INT, NO_TEXT);
1284  }
1285  
1286  //! @brief PROC (INT, INT) REAL ln choose
1287  
1288  void genie_ln_choose_real (NODE_T * p)
1289  {
1290    A68_INT n, m;
1291    POP_OBJECT (p, &m, A68_INT);
1292    POP_OBJECT (p, &n, A68_INT);
1293    errno = 0;
1294    PUSH_VALUE (p, a68_ln_choose_real (VALUE (&n), VALUE (&m)), A68_REAL);
1295    MATH_RTE (p, errno != 0, M_INT, NO_TEXT);
1296  }
1297  
1298  // OP / = (COMPLEX, COMPLEX) COMPLEX
1299  
1300  void a68_div_complex (A68_REAL * z, A68_REAL * x, A68_REAL * y)
1301  {
1302    STATUS_RE (z) = INIT_MASK;
1303    STATUS_IM (z) = INIT_MASK;
1304    if (RE (y) == 0 && IM (y) == 0) {
1305      RE (z) = 0.0;
1306      IM (z) = 0.0;
1307      errno = EDOM;
1308    } else if (fabs (RE (y)) >= fabs (IM (y))) {
1309      REAL_T r = IM (y) / RE (y), den = RE (y) + r * IM (y);
1310      RE (z) = (RE (x) + r * IM (x)) / den;
1311      IM (z) = (IM (x) - r * RE (x)) / den;
1312    } else {
1313      REAL_T r = RE (y) / IM (y), den = IM (y) + r * RE (y);
1314      RE (z) = (RE (x) * r + IM (x)) / den;
1315      IM (z) = (IM (x) * r - RE (x)) / den;
1316    }
1317  }
1318  
1319  // BITS max bits
1320  
1321  void genie_max_bits (NODE_T * p)
1322  {
1323    PUSH_VALUE (p, A68_MAX_BITS, A68_BITS);
1324  }
1325  
1326  // OP NOT = (BITS) BITS.
1327  A68_MONAD (genie_not_bits, A68_BITS, ~);
1328  
1329  // OP AND = (BITS, BITS) BITS
1330  
1331  void genie_and_bits (NODE_T * p)
1332  {
1333    A68_BITS *i, *j;
1334    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1335    VALUE (i) = VALUE (i) & VALUE (j);
1336  }
1337  
1338  // OP OR = (BITS, BITS) BITS
1339  
1340  void genie_or_bits (NODE_T * p)
1341  {
1342    A68_BITS *i, *j;
1343    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1344    VALUE (i) = VALUE (i) | VALUE (j);
1345  }
1346  
1347  // OP XOR = (BITS, BITS) BITS
1348  
1349  void genie_xor_bits (NODE_T * p)
1350  {
1351    A68_BITS *i, *j;
1352    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1353    VALUE (i) = VALUE (i) ^ VALUE (j);
1354  }
1355  
1356  // OP + = (BITS, BITS) BITS
1357  
1358  void genie_add_bits (NODE_T * p)
1359  {
1360    A68_BITS *i, *j;
1361    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1362    CHECK_BITS_ADDITION (p, VALUE (i), VALUE (j));
1363    VALUE (i) = VALUE (i) + VALUE (j);
1364  }
1365  
1366  // OP - = (BITS, BITS) BITS
1367  
1368  void genie_sub_bits (NODE_T * p)
1369  {
1370    A68_BITS *i, *j;
1371    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1372    CHECK_BITS_SUBTRACTION (p, VALUE (i), VALUE (j));
1373    VALUE (i) = VALUE (i) - VALUE (j);
1374  }
1375  
1376  // OP * = (BITS, BITS) BITS
1377  
1378  void genie_times_bits (NODE_T * p)
1379  {
1380    A68_BITS *i, *j;
1381    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1382    CHECK_BITS_MULTIPLICATION (p, VALUE (i), VALUE (j));
1383    VALUE (i) = VALUE (i) * VALUE (j);
1384  }
1385  
1386  // OP OVER = (BITS, BITS) BITS
1387  
1388  void genie_over_bits (NODE_T * p)
1389  {
1390    A68_BITS *i, *j;
1391    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1392    PRELUDE_ERROR (VALUE (j) == 0, p, ERROR_DIVISION_BY_ZERO, M_BITS);
1393    VALUE (i) = VALUE (i) / VALUE (j);
1394  }
1395  
1396  // OP MOD = (BITS, BITS) BITS
1397  
1398  void genie_mod_bits (NODE_T * p)
1399  {
1400    A68_BITS *i, *j;
1401    POP_OPERAND_ADDRESSES (p, i, j, A68_BITS);
1402    PRELUDE_ERROR (VALUE (j) == 0, p, ERROR_DIVISION_BY_ZERO, M_BITS);
1403    VALUE (i) = VALUE (i) % VALUE (j);
1404  }
1405  
1406  // OP = = (BITS, BITS) BOOL.
1407  
1408  #define A68_CMP_BITS(n, OP)\
1409  void n (NODE_T * p) {\
1410    A68_BITS i, j;\
1411    POP_OBJECT (p, &j, A68_BITS);\
1412    POP_OBJECT (p, &i, A68_BITS);\
1413    PUSH_VALUE (p, (BOOL_T) ((UNSIGNED_T) VALUE (&i) OP (UNSIGNED_T) VALUE (&j)), A68_BOOL);\
1414    }
1415  
1416  A68_CMP_BITS (genie_eq_bits, ==);
1417  A68_CMP_BITS (genie_ne_bits, !=);
1418  
1419  // OP <= = (BITS, BITS) BOOL
1420  
1421  void genie_le_bits (NODE_T * p)
1422  {
1423    A68_BITS i, j;
1424    POP_OBJECT (p, &j, A68_BITS);
1425    POP_OBJECT (p, &i, A68_BITS);
1426    PUSH_VALUE (p, (BOOL_T) ((VALUE (&i) | VALUE (&j)) == VALUE (&j)), A68_BOOL);
1427  }
1428  
1429  // OP >= = (BITS, BITS) BOOL
1430  
1431  void genie_ge_bits (NODE_T * p)
1432  {
1433    A68_BITS i, j;
1434    POP_OBJECT (p, &j, A68_BITS);
1435    POP_OBJECT (p, &i, A68_BITS);
1436    PUSH_VALUE (p, (BOOL_T) ((VALUE (&i) | VALUE (&j)) == VALUE (&i)), A68_BOOL);
1437  }
1438  
1439  #if (A68_LEVEL >= 3)
1440  
1441  // OP < = (BITS, BITS) BOOL
1442  
1443  void genie_lt_bits (NODE_T * p)
1444  {
1445    A68_BITS i, j;
1446    POP_OBJECT (p, &j, A68_BITS);
1447    POP_OBJECT (p, &i, A68_BITS);
1448    if (VALUE (&i) == VALUE (&j)) {
1449      PUSH_VALUE (p, A68_FALSE, A68_BOOL);
1450    } else {
1451      PUSH_VALUE (p, (BOOL_T) ((VALUE (&i) | VALUE (&j)) == VALUE (&j)), A68_BOOL);
1452    }
1453  }
1454  
1455  // OP >= = (BITS, BITS) BOOL
1456  
1457  void genie_gt_bits (NODE_T * p)
1458  {
1459    A68_BITS i, j;
1460    POP_OBJECT (p, &j, A68_BITS);
1461    POP_OBJECT (p, &i, A68_BITS);
1462    if (VALUE (&i) == VALUE (&j)) {
1463      PUSH_VALUE (p, A68_FALSE, A68_BOOL);
1464    } else {
1465      PUSH_VALUE (p, (BOOL_T) ((VALUE (&i) | VALUE (&j)) == VALUE (&i)), A68_BOOL);
1466    }
1467  }
1468  
1469  #endif
1470  
1471  // OP SHL = (BITS, INT) BITS
1472  
1473  void genie_shl_bits (NODE_T * p)
1474  {
1475    A68_BITS i; A68_INT j;
1476    POP_OBJECT (p, &j, A68_INT);
1477    POP_OBJECT (p, &i, A68_BITS);
1478    if (VALUE (&j) >= 0) {
1479      UNSIGNED_T z = VALUE (&i);
1480      for (int k = 0; k < VALUE (&j); k++) {
1481        PRELUDE_ERROR (!MODULAR_MATH (p) && (z & D_SIGN), p, ERROR_MATH, M_BITS);
1482        z = z << 1;
1483      }
1484      PUSH_VALUE (p, z, A68_BITS);
1485    } else {
1486      PUSH_VALUE (p, VALUE (&i) >> -VALUE (&j), A68_BITS);
1487    }
1488  }
1489  
1490  // OP SHR = (BITS, INT) BITS
1491  
1492  void genie_shr_bits (NODE_T * p)
1493  {
1494    A68_INT *j;
1495    POP_OPERAND_ADDRESS (p, j, A68_INT);
1496    VALUE (j) = -VALUE (j);
1497    genie_shl_bits (p);           // Conform RR
1498  }
1499  
1500  // OP ROL = (BITS, INT) BITS
1501  
1502  void genie_rol_bits (NODE_T * p)
1503  {
1504    A68_BITS i; A68_INT j;
1505    POP_OBJECT (p, &j, A68_INT);
1506    POP_OBJECT (p, &i, A68_BITS);
1507    CHECK_INT_SHORTEN (p, VALUE (&j));
1508    UNSIGNED_T w = VALUE (&i);
1509    int n = VALUE (&j);
1510    if (n >= 0) {
1511      for (int k = 0; k < n; k++) {
1512        UNSIGNED_T carry = (w & D_SIGN ? 0x1 : 0x0);
1513        w = (w << 1) | carry;
1514      }
1515    } else {
1516      n = -n;
1517      for (int k = 0; k < n; k++) {
1518        UNSIGNED_T carry = (w & 0x1 ? D_SIGN : 0x0);
1519        w = (w >> 1) | carry;
1520      }
1521    }
1522    PUSH_VALUE (p, w, A68_BITS);
1523  }
1524  
1525  // OP ROR = (BITS, INT) BITS
1526  
1527  void genie_ror_bits (NODE_T * p)
1528  {
1529    A68_INT *j;
1530    POP_OPERAND_ADDRESS (p, j, A68_INT);
1531    VALUE (j) = -VALUE (j);
1532    genie_rol_bits (p);
1533  }
1534  
1535  // OP ELEM = (INT, BITS) BOOL
1536  
1537  void genie_elem_bits (NODE_T * p)
1538  {
1539    A68_BITS j; A68_INT i;
1540    UNSIGNED_T mask = 0x1;
1541    POP_OBJECT (p, &j, A68_BITS);
1542    POP_OBJECT (p, &i, A68_INT);
1543    PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1544    for (int n = 0; n < (A68_BITS_WIDTH - VALUE (&i)); n++) {
1545      mask = mask << 1;
1546    }
1547    PUSH_VALUE (p, (BOOL_T) ((VALUE (&j) & mask) != 0 ? A68_TRUE : A68_FALSE), A68_BOOL);
1548  }
1549  
1550  // OP SET = (INT, BITS) BITS
1551  
1552  void genie_set_bits (NODE_T * p)
1553  {
1554    A68_BITS j; A68_INT i;
1555    UNSIGNED_T mask = 0x1;
1556    POP_OBJECT (p, &j, A68_BITS);
1557    POP_OBJECT (p, &i, A68_INT);
1558    PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1559    for (int n = 0; n < (A68_BITS_WIDTH - VALUE (&i)); n++) {
1560      mask = mask << 1;
1561    }
1562    PUSH_VALUE (p, VALUE (&j) | mask, A68_BITS);
1563  }
1564  
1565  // OP CLEAR = (INT, BITS) BITS
1566  
1567  void genie_clear_bits (NODE_T * p)
1568  {
1569    A68_BITS j; A68_INT i;
1570    UNSIGNED_T mask = 0x1;
1571    POP_OBJECT (p, &j, A68_BITS);
1572    POP_OBJECT (p, &i, A68_INT);
1573    PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
1574    for (int n = 0; n < (A68_BITS_WIDTH - VALUE (&i)); n++) {
1575      mask = mask << 1;
1576    }
1577    PUSH_VALUE (p, VALUE (&j) & ~mask, A68_BITS);
1578  }
1579  
1580  // OP ABS = (BITS) INT
1581  
1582  void genie_abs_bits (NODE_T * p)
1583  {
1584    A68_BITS i;
1585    POP_OBJECT (p, &i, A68_BITS);
1586    PUSH_VALUE (p, (INT_T) (VALUE (&i)), A68_INT);
1587  }
1588  
1589  // OP BIN = (INT) BITS
1590  
1591  void genie_bin_int (NODE_T * p)
1592  {
1593    A68_INT i;
1594    POP_OBJECT (p, &i, A68_INT);
1595    if (!MODULAR_MATH (p) && VALUE (&i) < 0) {
1596  // RR does not convert negative numbers.
1597      errno = EDOM;
1598      diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, M_BITS);
1599      exit_genie (p, A68_RUNTIME_ERROR);
1600    }
1601    PUSH_VALUE (p, (UNSIGNED_T) (VALUE (&i)), A68_BITS);
1602  }
1603  
1604  // @brief PROC ([] BOOL) BITS bits pack
1605  
1606  void genie_bits_pack (NODE_T * p)
1607  {
1608    A68_ARRAY *arr; A68_TUPLE *tup;
1609    A68_REF z;
1610    POP_REF (p, &z);
1611    CHECK_REF (p, z, M_ROW_BOOL);
1612    GET_DESCRIPTOR (arr, tup, &z);
1613    int size = ROW_SIZE (tup);
1614    PRELUDE_ERROR (size < 0 || size > A68_BITS_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_ROW_BOOL);
1615    A68_BITS b;
1616    VALUE (&b) = 0x0;
1617    if (ROW_SIZE (tup) > 0) {
1618      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
1619      UNSIGNED_T bit = 0x1;
1620      for (int k = UPB (tup); k >= LWB (tup); k--) {
1621        int addr = INDEX_1_DIM (arr, tup, k);
1622        A68_BOOL *boo = (A68_BOOL *) & (base[addr]);
1623        CHECK_INIT (p, INITIALISED (boo), M_BOOL);
1624        if (VALUE (boo)) {
1625          VALUE (&b) |= bit;
1626        }
1627        bit <<= 1;
1628      }
1629    }
1630    STATUS (&b) = INIT_MASK;
1631    PUSH_OBJECT (p, b, A68_BITS);
1632  }