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-2025 J. Marcel van der Veer <algol68g@xs4all.nl>.
8 //
9 //! @section License
10 //
11 // This program is free software; you can redistribute it and/or modify it
12 // under the terms of the GNU General Public License as published by the
13 // Free Software Foundation; either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 // more details. You should have received a copy of the GNU General Public
20 // License along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22 //! @section Synopsis
23 //!
24 //! 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 ten_up_double (int_4 expo)
35 {
36 // This way appears sufficiently accurate.
37 real_16 dbl_expo = 1.0q, *dep;
38 logical_4 neg_expo;
39 if (expo == 0) {
40 return 1.0q;
41 }
42 neg_expo = (logical_4) (expo < 0);
43 if (neg_expo) {
44 expo = -expo;
45 }
46 if (expo > MAX_DOUBLE_EXPO) {
47 expo = 0;
48 errno = EDOM;
49 }
50 // ABEND (expo > MAX_DOUBLE_EXPO, ERROR_INVALID_VALUE, __func__);
51 for (dep = pow_10_double; expo != 0; expo >>= 1, dep++) {
52 if (expo & 0x1) {
53 dbl_expo *= *dep;
54 }
55 }
56 return neg_expo ? 1.0q / dbl_expo : dbl_expo;
57 }
58
59 //! @brief Transform string into real-16.
60 // From Algol 68 Genie.
61
62 real_16 _strtoquad (char *s, char **end)
63 {
64 int_4 i, dot = -1, pos = 0, pow = 0, expo;
65 real_16 sum, W, y[FLT128_DIG];
66 errno = 0;
67 for (i = 0; i < FLT128_DIG; i++) {
68 y[i] = 0.0q;
69 }
70 while (isspace (s[0])) {
71 s++;
72 }
73 // Scan mantissa digits and put them into "y".
74 if (s[0] == '-') {
75 W = -1.0q;
76 } else {
77 W = 1.0q;
78 }
79 if (s[0] == '+' || s[0] == '-') {
80 s++;
81 }
82 while (s[0] == '0') {
83 s++;
84 }
85 while (pow < FLT128_DIG && s[pos] != '\0' && (isdigit (s[pos]) || s[pos] == '.')) {
86 if (s[pos] == '.') {
87 dot = pos;
88 } else {
89 int_4 val = (int_4) s[pos] - (int_4) '0';
90 y[pow] = W * val;
91 W /= 10.0q;
92 pow++;
93 }
94 pos++;
95 }
96 if (end != NO_REF_TEXT) {
97 (*end) = &(s[pos]);
98 }
99 // Sum from low to high to preserve precision.
100 sum = 0.0q;
101 for (i = FLT128_DIG - 1; i >= 0; i--) {
102 sum = sum + y[i];
103 }
104 // See if there is an exponent.
105 if (_EXPCHAR (s[pos])) {
106 expo = (int_4) strtol (&(s[++pos]), end, 10);
107 } else {
108 expo = 0;
109 }
110 // Standardise.
111 if (dot >= 0) {
112 expo += dot - 1;
113 } else {
114 expo += pow - 1;
115 }
116 while (sum != 0.0q && fabsq (sum) < 1.0q) {
117 sum *= 10.0q;
118 expo -= 1;
119 }
120 //
121 if (errno == 0) {
122 return sum * ten_up_double (expo);
123 } else {
124 return 0.0q;
125 }
126 }
127
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|