rts-real16.c

     
   1  //! @file rts-real16.c
   2  //! @author J. Marcel van der Veer
   3  //
   4  //! @section Copyright
   5  //
   6  // This file is part of VIF - vintage FORTRAN compiler.
   7  // Copyright 2020-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  //! Runtime support for REAL*16 and COMPLEX*32.
  25  
  26  #include <vif.h>
  27  
  28  #define MAX_DOUBLE_EXPO 4932
  29  
  30  static real_16 pow_10_double[] = {
  31    10.0q, 100.0q, 1.0e4q, 1.0e8q, 1.0e16q, 1.0e32q, 1.0e64q, 1.0e128q, 1.0e256q, 1.0e512q, 1.0e1024q, 1.0e2048q, 1.0e4096q
  32  };
  33  
  34  real_16 _qnint (real_16 x)
  35  {
  36    return (x >= 0 ? floorq (0.5q + x) : - floorq (0.5q - x));
  37  }
  38  
  39  real_16 ten_up_double (int_4 expo)
  40  {
  41  // This way appears sufficiently accurate.
  42    real_16 dbl_expo = 1.0q, *dep;
  43    logical_4 neg_expo;
  44    if (expo == 0) {
  45      return 1.0q;
  46    }
  47    neg_expo = (logical_4) (expo < 0);
  48    if (neg_expo) {
  49      expo = -expo;
  50    }
  51    if (expo > MAX_DOUBLE_EXPO) {
  52      expo = 0;
  53      errno = EDOM;
  54    }
  55  //  ABEND (expo > MAX_DOUBLE_EXPO, ERROR_INVALID_VALUE, __func__);
  56    for (dep = pow_10_double; expo != 0; expo >>= 1, dep++) {
  57      if (expo & 0x1) {
  58        dbl_expo *= *dep;
  59      }
  60    }
  61    return neg_expo ? 1.0q / dbl_expo : dbl_expo;
  62  }
  63  
  64  //! @brief Transform string into real-16.
  65  // From Algol 68 Genie.
  66  
  67  real_16 _strtoquad (char *s, char **end)
  68  {
  69    int_4 i, dot = -1, pos = 0, pow = 0, expo;
  70    real_16 sum, W, y[FLT128_DIG];
  71    errno = 0;
  72    for (i = 0; i < FLT128_DIG; i++) {
  73      y[i] = 0.0q;
  74    }
  75    while (isspace (s[0])) {
  76      s++;
  77    }
  78  // Scan mantissa digits and put them into "y".
  79    if (s[0] == '-') {
  80      W = -1.0q;
  81    } else {
  82      W = 1.0q;
  83    }
  84    if (s[0] == '+' || s[0] == '-') {
  85      s++;
  86    }
  87    while (s[0] == '0') {
  88      s++;
  89    }
  90    while (pow < FLT128_DIG && s[pos] != '\0' && (isdigit (s[pos]) || s[pos] == '.')) {
  91      if (s[pos] == '.') {
  92        dot = pos;
  93      } else {
  94        int_4 val = (int_4) s[pos] - (int_4) '0';
  95        y[pow] = W * val;
  96        W /= 10.0q;
  97        pow++;
  98      }
  99      pos++;
 100    }
 101    if (end != NULL) {
 102      (*end) = &(s[pos]);
 103    }
 104  // Sum from low to high to preserve precision.
 105    sum = 0.0q;
 106    for (i = FLT128_DIG - 1; i >= 0; i--) {
 107      sum = sum + y[i];
 108    }
 109  // See if there is an exponent.
 110    if (_EXPCHAR (s[pos])) {
 111      expo = (int_4) strtol (&(s[++pos]), end, 10);
 112    } else {
 113      expo = 0;
 114    }
 115  // Standardise.
 116    if (dot >= 0) {
 117      expo += dot - 1;
 118    } else {
 119      expo += pow - 1;
 120    }
 121    while (sum != 0.0q && fabsq (sum) < 1.0q) {
 122      sum *= 10.0q;
 123      expo -= 1;
 124    }
 125  //
 126    if (errno == 0) {
 127      return sum * ten_up_double (expo);
 128    } else {
 129      return 0.0q;
 130    }
 131  }
 132  
     


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