rts-math.c
1 //! @file rts-math.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 math operations.
25
26 #include <vif.h>
27
28 // INTEGER*4
29
30 int_4 _up_int_4 (int_4 m, int_4 n)
31 {
32 // Special cases.
33 if (m == 2 && n >= 0) {
34 return 1 << n;
35 } else if (m == 1) {
36 return m;
37 } else if (m == -1) {
38 return (n % 2 == 0 ? 1 : -1);
39 } else if (m == 0) {
40 return (n == 0 ? 1 : 0);
41 } else if (n < 0) {
42 return 0;
43 }
44 // General case.
45 unsigned bit = 1;
46 int_4 M = m, P = 1;
47 do {
48 if (n & bit) {
49 P *= M;
50 }
51 bit <<= 1;
52 if ((int_4) bit <= n) {
53 M *= M;
54 }
55 } while ((int_4) bit <= n);
56 return P;
57 }
58
59 // INTEGER*8
60
61 int_8 _up_int_8 (int_8 m, int_4 n)
62 {
63 // Special cases.
64 if (m == 2 && n >= 0) {
65 int_8 s = 1;
66 s <<= n;
67 return s;
68 } else if (m == 1) {
69 return m;
70 } else if (m == -1) {
71 return (n % 2 == 0 ? 1 : -1);
72 } else if (m == 0) {
73 return (n == 0 ? 1 : 0);
74 } else if (n < 0) {
75 return 0;
76 }
77 // General case.
78 unsigned bit = 1;
79 int_8 M = m, P = 1;
80 do {
81 if (n & bit) {
82 P *= M;
83 }
84 bit <<= 1;
85 if ((int_4) bit <= n) {
86 M *= M;
87 }
88 } while ((int_4) bit <= n);
89 return P;
90 }
91
92 // REAL*4
93
94 real_4 _up_real_4 (real_4 x, int_4 n)
95 {
96 // Only positive n.
97 if (n < 0) {
98 return 1 / _up_real_4 (x, -n);
99 }
100 // Special cases.
101 if (x == 0 || x == 1) {
102 return x;
103 } else if (x == -1) {
104 return (n % 2 == 0 ? 1 : -1);
105 }
106 // General case.
107 unsigned bit = 1;
108 real_4 M = x, P = 1;
109 do {
110 if (n & bit) {
111 P *= M;
112 }
113 bit <<= 1;
114 if ((int_4) bit <= n) {
115 M *= M;
116 }
117 } while ((int_4) bit <= n);
118 return P;
119 }
120
121 real_4 cotanf (real_4 x)
122 {
123 return 1.0 / tanf (x);
124 }
125
126 real_4 acotanf (real_4 x)
127 {
128 return atanf (1 / x);
129 }
130
131 // REAL*8
132
133 real_8 _up_real_8 (real_8 x, int_4 n)
134 {
135 // Only positive n.
136 if (n < 0) {
137 return 1 / _up_real_8 (x, -n);
138 }
139 // Special cases.
140 if (x == 0 || x == 1) {
141 return x;
142 } else if (x == -1) {
143 return (n % 2 == 0 ? 1 : -1);
144 }
145 // General case.
146 unsigned bit = 1;
147 real_8 M = x, P = 1;
148 do {
149 if (n & bit) {
150 P *= M;
151 }
152 bit <<= 1;
153 if ((int_4) bit <= n) {
154 M *= M;
155 }
156 } while ((int_4) bit <= n);
157 return P;
158 }
159
160 real_8 cotan (real_8 x)
161 {
162 return 1.0 / tan (x);
163 }
164
165 real_8 acotan (real_8 x)
166 {
167 return atan (1 / x);
168 }
169
170 real_8 _vif_inverfc (real_8 y)
171 {
172 #define N_c_inverfc 34
173
174 static const real_8 c_inverfc[N_c_inverfc] = {
175 0.91646139826896400000,
176 0.48882664027310800000,
177 0.23172920032340500000,
178 0.12461045461371200000,
179 -0.07288467655856750000,
180 0.26999930867002900000,
181 0.15068904736022300000,
182 0.11606502534161400000,
183 0.49999930343979000000,
184 3.97886080735226000000,
185 0.00112648096188977922,
186 1.05739299623423047e-4,
187 0.00351287146129100025,
188 7.71708358954120939e-4,
189 0.00685649426074558612,
190 0.00339721910367775861,
191 0.01127491693325048700,
192 0.01185981170477711040,
193 0.01429619886978980180,
194 0.03464942077890999220,
195 0.00220995927012179067,
196 0.07434243572417848610,
197 0.10587217794159548800,
198 0.01472979383314851210,
199 0.31684763852013594400,
200 0.71365763586873036400,
201 1.05375024970847138000,
202 1.21448730779995237000,
203 1.16374581931560831000,
204 0.95646497474479900600,
205 0.68626594827409781600,
206 0.43439749233143011500,
207 0.24404451059319093500,
208 0.12078223763524522200
209 };
210
211 if (y < 0 || y > 2) {
212 errno = ERANGE;
213 return 0;
214 }
215 if (y == 0) {
216 return DBL_MAX;
217 } else if (y == 1) {
218 return 0;
219 } else if (y == 2) {
220 return -DBL_MAX;
221 } else {
222 // Next is based on code that originally contained following statement:
223 // Copyright (c) 1996 Takuya Ooura. You may use, copy, modify this
224 // code for any purpose and without fee.
225 real_8 s, t, u, v, x, z;
226 z = (y <= 1 ? y : 2 - y);
227 v = c_inverfc[0] - ln (z);
228 u = sqrt (v);
229 s = (ln (u) + c_inverfc[1]) / v;
230 t = 1 / (u + c_inverfc[2]);
231 x = u *(1 - s *(s *c_inverfc[3] + 0.5)) - ((((c_inverfc[4] *t + c_inverfc[5]) *t + c_inverfc[6]) *t + c_inverfc[7]) *t + c_inverfc[8]) *t;
232 t = c_inverfc[9] / (x + c_inverfc[9]);
233 u = t - 0.5;
234 s = (((((((((c_inverfc[10] *u + c_inverfc[11]) *u - c_inverfc[12]) *u - c_inverfc[13]) *u + c_inverfc[14]) *u + c_inverfc[15]) *u - c_inverfc[16]) *u - c_inverfc[17]) *u + c_inverfc[18]) *u + c_inverfc[19]) *u + c_inverfc[20];
235 s = ((((((((((((s *u - c_inverfc[21]) *u - c_inverfc[22]) *u + c_inverfc[23]) *u + c_inverfc[24]) *u + c_inverfc[25]) *u + c_inverfc[26]) *u + c_inverfc[27]) *u + c_inverfc[28]) *u + c_inverfc[29]) *u + c_inverfc[30]) *u + c_inverfc[31]) *u + c_inverfc[32]) *t - z *exp (x *x - c_inverfc[33]);
236 x += s *(x *s + 1);
237 return (y <= 1 ? x : -x);
238 }
239 }
240
241 real_8 _vif_inverf (real_8 y)
242 {
243 return _vif_inverfc (1 - y);
244 }
245
246 void _merfi (real_8 *p, real_8 *x, int_4 *err)
247 {
248 (*x) = _vif_inverf (*p);
249 (*err) = errno;
250 }
251
252 // REAL*16
253
254 real_16 _qext (real_8 x)
255 {
256 /*
257 NEW_RECORD (str);
258 _srecordf (str, "%.*le", DBL_DIG, x);
259 return _strtoquad (str, NO_REF_TEXT);
260 */
261 return (real_16) x;
262 }
263
264 real_16 _qmod (real_16 x, real_16 y)
265 {
266 real_16 q;
267 if ((q = x / y) >= 0) {
268 q = floorq (q);
269 } else {
270 q = -floorq (-q);
271 }
272 return (x - y *q);
273 }
274
275 real_16 _up_real_16 (real_16 x, int_4 n)
276 {
277 // Only positive n.
278 if (n < 0) {
279 return 1.0q / _up_real_16 (x, -n);
280 }
281 // Special cases.
282 if (x == 0.0q || x == 1.0q) {
283 return x;
284 } else if (x == -1.0q) {
285 return (n % 2 == 0 ? 1.0q : -1.0q);
286 }
287 // General case.
288 unsigned bit = 1;
289 real_16 M = x, P = 1.0q;
290 do {
291 if (n & bit) {
292 P *= M;
293 }
294 bit <<= 1;
295 if ((int_4) bit <= n) {
296 M *= M;
297 }
298 } while ((int_4) bit <= n);
299 return P;
300 }
301
302 real_16 cotanq (real_16 x)
303 {
304 return 1.0q / tanq (x);
305 }
306
307 real_16 acotanq (real_16 x)
308 {
309 return atanq (1 / x);
310 }
311
312 // COMPLEX*8
313
314 complex_8 _cmplxd (complex_16 z)
315 {
316 return CMPLXF ((real_4) creal (z), (real_4) cimag (z));
317 }
318
319 complex_8 _up_complex_8 (complex_8 x, int_4 n)
320 {
321 // Only positive n.
322 if (n < 0) {
323 return 1 / _up_complex (x, -n);
324 }
325 // General case.
326 unsigned bit = 1;
327 complex_8 M = x, P = 1;
328 do {
329 if (n & bit) {
330 P *= M;
331 }
332 bit <<= 1;
333 if ((int_4) bit <= n) {
334 M *= M;
335 }
336 } while ((int_4) bit <= n);
337 return P;
338 }
339
340 // COMPLEX*16
341
342 complex_16 _dcmplxq (complex_32 z)
343 {
344 return CMPLX (crealq (z), cimagq (z));
345 }
346
347 complex_16 _up_complex (complex_16 x, int_4 n)
348 {
349 // Only positive n.
350 if (n < 0) {
351 return 1 / _up_complex (x, -n);
352 }
353 // General case.
354 unsigned bit = 1;
355 complex_16 M = x, P = 1;
356 do {
357 if (n & bit) {
358 P *= M;
359 }
360 bit <<= 1;
361 if ((int_4) bit <= n) {
362 M *= M;
363 }
364 } while ((int_4) bit <= n);
365 return P;
366 }
367
368 // COMPLEX*32
369
370 complex_32 _qcmplxd (complex_16 z)
371 {
372 return CMPLXQ (_qext (creal (z)), _qext (cimag (z)));
373 }
374
375 complex_32 _up_complex_32 (complex_32 x, int_4 n)
376 {
377 // Only positive n.
378 if (n < 0) {
379 return 1.0q / _up_complex_32 (x, -n);
380 }
381 // General case.
382 unsigned bit = 1;
383 complex_32 M = x, P = 1.0q;
384 do {
385 if (n & bit) {
386 P *= M;
387 }
388 bit <<= 1;
389 if ((int_4) bit <= n) {
390 M *= M;
391 }
392 } while ((int_4) bit <= n);
393 return P;
394 }
395
396 real_4 _zabs_8 (real_4 re, real_4 im)
397 {
398 return cabsf (CMPLXF (re, im));
399 }
400
401 real_8 _zabs_16 (real_8 re, real_8 im)
402 {
403 return cabs (CMPLX (re, im));
404 }
405
406 real_16 _zabs_32 (real_16 re, real_16 im)
407 {
408 return cabsq (CMPLXQ (re, im));
409 }
410
411 void _qhex (real_16 *u)
412 {
413 unt_2 *p = (unt_2 *) u;
414 fprintf (stdout, "{");
415 for (int_4 i = 0; i <= FLT128_LEN; i++) {
416 fprintf (stdout, "0x%04x", *(p++));
417 if (i < FLT128_LEN) {
418 fprintf (stdout, ", ");
419 }
420 }
421 fprintf (stdout, "}\n");
422 }
423
424 void _xhex (real_32 *u)
425 {
426 fprintf (stdout, "{");
427 for (int_4 i = 0; i <= FLT256_LEN; i++) {
428 fprintf (stdout, "0x%04x", u->value[i]);
429 if (i < FLT256_LEN) {
430 fprintf (stdout, ", ");
431 }
432 }
433 fprintf (stdout, "}\n");
434 }
435
436 //
437
438 void _pi4 (real_4 * x)
439 {
440 *x = (real_4) M_PI;
441 }
442
443 void _pi8 (real_8 * x)
444 {
445 *x = M_PI;
446 }
447
448 void _pi16 (real_16 * x)
449 {
450 *x = M_PIq;
451 }
© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)
|