quad.c
1 //! @file quad.c
2 //!
3 //! @author (see below)
4 //!
5 //! @section Copyright
6 //!
7 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
8 //! Copyright 2001-2023 J. Marcel van der Veer [algol68g@xs4all.nl].
9 //!
10 //! @section License
11 //!
12 //! This program is free software; you can redistribute it and/or modify it
13 //! under the terms of the GNU General Public License as published by the
14 //! Free Software Foundation; either version 3 of the License, or
15 //! (at your option) any later version.
16 //!
17 //! This program is distributed in the hope that it will be useful, but
18 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 //! more details. You should have received a copy of the GNU General Public
21 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
22
23 //! @section Synopsis
24 //!
25 //! Fixed precision LONG LONG REAL/COMPLEX library.
26
27 // A68G has an own LONG LONG REAL library with variable precision.
28 // This fixed-length library serves as more economical double precision
29 // to double real, for instance in computing the incomplete gamma function.
30 //
31 // This code is based on the HPA Library, a branch of the CCMath library.
32 // The CCMath library and derived HPA Library are free software under the terms
33 // of the GNU Lesser General Public License version 2.1 or any later version.
34 //
35 // Sources:
36 // [https://directory.fsf.org/wiki/HPAlib]
37 // [http://download-mirror.savannah.gnu.org/releases/hpalib/]
38 // [http://savannah.nongnu.org/projects/hpalib]
39 //
40 // Copyright 2000 Daniel A. Atkinson [DanAtk@aol.com]
41 // Copyright 2004 Ivano Primi [ivprimi@libero.it]
42 // Copyright 2023 Marcel van der Veer [algol68g@xs4all.nl] - A68G version.
43
44 // IEEE 754 floating point standard is assumed.
45 // A quad real number is represented as:
46 //
47 // Sign bit(s): 0 -> positive, 1 -> negative.
48 // Exponent(e): 15-bit biased integer (bias = 16383).
49 // Mantissa(m): 15 words of 16 bit length including leading 1.
50 //
51 // The range of representable numbers is then given by
52 //
53 // 2^16384 > x > 2^[-16383]
54 // 1.19*10^4932 > x > 1.68*10^-[4932]
55 //
56 // Special values of the exponent are:
57 //
58 // All 1 -> infinity (floating point overflow).
59 // All 0 -> number equals zero.
60 //
61 // Underflow in operations is handled by a flush to zero. Thus, a number
62 // with the exponent zero and nonzero mantissa is invalid (not-a-number).
63 // A complex number is a structure formed by two REAL*32 numbers.
64 //
65 // HPA cannot extend precision beyond the preset, hardcoded precision.
66 // Hence some math routines will not achieve full precision.
67
68 #include "a68g.h"
69
70 #if (A68_LEVEL >= 3)
71
72 #include "a68g-quad.h"
73
74 // Constants, extended with respect to original HPA lib.
75
76 const int_2 QUAD_REAL_BIAS = 16383;
77 const int_2 QUAD_REAL_DBL_BIAS = 15360;
78 const int_2 QUAD_REAL_DBL_LEX = 12;
79 const int_2 QUAD_REAL_DBL_MAX = 2047;
80 const int_2 QUAD_REAL_K_LIN = -8 * FLT256_LEN;
81 const int_2 QUAD_REAL_MAX_P = 16 * FLT256_LEN;
82 const QUAD_T QUAD_REAL_E2MAX = {{0x400c, 0xfffb}}; // +16382.75
83 const QUAD_T QUAD_REAL_E2MIN = {{0xc00c, 0xfffb}}; // -16382.75
84 const QUAD_T QUAD_REAL_EMAX = {{0x400c, 0xb16c}};
85 const QUAD_T QUAD_REAL_EMIN = {{0xc00c, 0xb16c}};
86 const QUAD_T QUAD_REAL_MINF = {{0xffff, 0x0}};
87 const QUAD_T QUAD_REAL_PINF = {{0x7fff, 0x0}};
88 const QUAD_T QUAD_REAL_VGV = {{0x4013, 0x8000}};
89 const QUAD_T QUAD_REAL_VSV = {{0x3ff2, 0x8000}};
90 const unt_2 QUAD_REAL_M_EXP = 0x7fff;
91 const unt_2 QUAD_REAL_M_SIGN = 0x8000;
92
93 const QUAD_T QUAD_REAL_ZERO =
94 {{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
95 const QUAD_T QUAD_REAL_TENTH =
96 {{0x3ffb, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc}};
97 const QUAD_T QUAD_REAL_HALF =
98 {{0x3ffe, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
99 const QUAD_T QUAD_REAL_ONE =
100 {{0x3fff, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
101 const QUAD_T QUAD_REAL_TWO =
102 {{0x4000, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
103 const QUAD_T QUAD_REAL_TEN =
104 {{0x4002, 0xa000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
105 const QUAD_T QUAD_REAL_HUNDRED =
106 {{0x4005, 0xc800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
107 const QUAD_T QUAD_REAL_THOUSAND =
108 {{0x4008, 0xfa00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
109 const QUAD_T QUAD_REAL_PI4 =
110 {{0x3ffe, 0xc90f, 0xdaa2, 0x2168, 0xc234, 0xc4c6, 0x628b, 0x80dc, 0x1cd1, 0x2902, 0x4e08, 0x8a67, 0xcc74, 0x020b, 0xbea6, 0x3b14}};
111 const QUAD_T QUAD_REAL_PI2 =
112 {{0x3fff, 0xc90f, 0xdaa2, 0x2168, 0xc234, 0xc4c6, 0x628b, 0x80dc, 0x1cd1, 0x2902, 0x4e08, 0x8a67, 0xcc74, 0x020b, 0xbea6, 0x3b14}};
113 const QUAD_T QUAD_REAL_PI =
114 {{0x4000, 0xc90f, 0xdaa2, 0x2168, 0xc234, 0xc4c6, 0x628b, 0x80dc, 0x1cd1, 0x2902, 0x4e08, 0x8a67, 0xcc74, 0x020b, 0xbea6, 0x3b14}};
115 const QUAD_T QUAD_REAL_LN2 =
116 {{0x3ffe, 0xb172, 0x17f7, 0xd1cf, 0x79ab, 0xc9e3, 0xb398, 0x03f2, 0xf6af, 0x40f3, 0x4326, 0x7298, 0xb62d, 0x8a0d, 0x175b, 0x8bab}};
117 const QUAD_T QUAD_REAL_LN10 =
118 {{0x4000, 0x935d, 0x8ddd, 0xaaa8, 0xac16, 0xea56, 0xd62b, 0x82d3, 0x0a28, 0xe28f, 0xecf9, 0xda5d, 0xf90e, 0x83c6, 0x1e82, 0x01f0}};
119 const QUAD_T QUAD_REAL_SQRT2 =
120 {{0x3fff, 0xb504, 0xf333, 0xf9de, 0x6484, 0x597d, 0x89b3, 0x754a, 0xbe9f, 0x1d6f, 0x60ba, 0x893b, 0xa84c, 0xed17, 0xac85, 0x8334}};
121 const QUAD_T QUAD_REAL_LOG2_E =
122 {{0x3fff, 0xb8aa, 0x3b29, 0x5c17, 0xf0bb, 0xbe87, 0xfed0, 0x691d, 0x3e88, 0xeb57, 0x7aa8, 0xdd69, 0x5a58, 0x8b25, 0x166c, 0xd1a1}};
123 const QUAD_T QUAD_REAL_LOG2_10 =
124 {{0x4000, 0xd49a, 0x784b, 0xcd1b, 0x8afe, 0x492b, 0xf6ff, 0x4daf, 0xdb4c, 0xd96c, 0x55fe, 0x37b3, 0xad4e, 0x91b6, 0xac80, 0x82e8}};
125 const QUAD_T QUAD_REAL_LOG10_E =
126 {{0x3ffd, 0xde5b, 0xd8a9, 0x3728, 0x7195, 0x355b, 0xaaaf, 0xad33, 0xdc32, 0x3ee3, 0x4602, 0x45c9, 0xa202, 0x3a3f, 0x2d44, 0xf78f}};
127 const QUAD_T QUAD_REAL_RNDCORR =
128 {{0x3ffe, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01ae}};
129 const QUAD_T QUAD_REAL_FIXCORR =
130 {{0x3f17, 0xc000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}};
131 const QUAD_T QUAD_REAL_NAN =
132 {{0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}};
133
134 static const char *errmsg[] = {
135 "No error",
136 "Division by zero",
137 "Out of domain",
138 "Bad exponent",
139 "Floating point overflow",
140 "Invalid error code"
141 };
142
143 static QUAD_T c_tan (QUAD_T u);
144 static QUAD_T rred (QUAD_T u, int i, int *p);
145
146 //! @brief _pi32
147
148 void _pi32 (QUAD_T *x)
149 {
150 *x = QUAD_REAL_PI;
151 }
152
153 //! @brief sigerr_quad_real
154
155 int sigerr_quad_real (int errcond, int errcode, const char *where)
156 {
157 // errcode must come from the evaluation of an error condition.
158 // errcode, which should describe the type of the error,
159 // should always be one between QUAD_REAL_EDIV, QUAD_REAL_EDOM, QUAD_REAL_EBADEXP and QUAD_REAL_FPOFLOW.
160 if (errcond == 0) {
161 errcode = 0;
162 }
163 if (errcode < 0 || errcode > QUAD_REAL_NERR) {
164 errcode = QUAD_REAL_EINV;
165 }
166 if (errcode != 0) {
167 QUAD_RTE (where, errmsg[errcode]);
168 }
169 return errcode;
170 }
171
172 // Elementary stuff.
173
174 //! @brief neg_quad_real
175
176 inline QUAD_T neg_quad_real (QUAD_T s)
177 {
178 unt_2 *p = (unt_2 *) &QV (s);
179 *p ^= QUAD_REAL_M_SIGN;
180 return s;
181 }
182
183 //! @brief abs_quad_real
184
185 inline QUAD_T abs_quad_real (QUAD_T s)
186 {
187 unt_2 *p = (unt_2 *) &QV (s);
188 *p &= QUAD_REAL_M_EXP;
189 return s;
190 }
191
192 //! @brief getexp_quad_real
193
194 inline int getexp_quad_real (const QUAD_T * ps)
195 {
196 unt_2 *q = (unt_2 *) &(ps->value);
197 return (*q & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS;
198 }
199
200 //! @brief getsgn_quad_real
201
202 inline int getsgn_quad_real (const QUAD_T * ps)
203 {
204 unt_2 *q = (unt_2 *) &(ps->value);
205 return (*q & QUAD_REAL_M_SIGN);
206 }
207
208 //! @brief real_cmp_quad_real
209
210 int real_cmp_quad_real (const QUAD_T * pa, const QUAD_T * pb)
211 {
212 unt_2 *p = (unt_2 *) &(pa->value), *q = (unt_2 *) &(pb->value);
213 unt_2 p0, q0;
214 int m;
215 for (m = 1; m <= FLT256_LEN && p[m] == 0; m++);
216 if (m > FLT256_LEN && (*p & QUAD_REAL_M_EXP) < QUAD_REAL_M_EXP) {
217 // *pa is actually zero
218 p0 = 0;
219 } else {
220 p0 = *p;
221 }
222 for (m = 1; m <= FLT256_LEN && q[m] == 0; m++);
223 if (m > FLT256_LEN && (*q & QUAD_REAL_M_EXP) < QUAD_REAL_M_EXP) {
224 // *pb is actually zero
225 q0 = 0;
226 } else {
227 q0 = *q;
228 }
229 unt_2 e = p0 & QUAD_REAL_M_SIGN, k = q0 & QUAD_REAL_M_SIGN;
230 if (e && !k) {
231 return -1;
232 } else if (!e && k) {
233 return 1;
234 } else { // *pa and *pb have the same sign
235 m = (e) ? -1 : 1;
236 e = p0 & QUAD_REAL_M_EXP;
237 k = q0 & QUAD_REAL_M_EXP;
238 if (e > k) {
239 return m;
240 } else if (e < k) {
241 return -m;
242 } else {
243 for (e = 0; *(++p) == *(++q) && e < FLT256_LEN; ++e);
244 if (e < FLT256_LEN) {
245 return (*p > *q ? m : -m);
246 } else {
247 return 0;
248 }
249 }
250 }
251 }
252
253 //! @brief real_2_quad_real
254
255 QUAD_T real_2_quad_real (QUAD_T s, int m)
256 {
257 unt_2 *p = (unt_2 *) &QV (s);
258 int e;
259 for (e = 1; e <= FLT256_LEN && p[e] == 0; e++);
260 if (e <= FLT256_LEN) {
261 e = *p & QUAD_REAL_M_EXP; // biased exponent
262 if (e + m < 0) {
263 return QUAD_REAL_ZERO;
264 } else if ((sigerr_quad_real (e + m >= QUAD_REAL_M_EXP, QUAD_REAL_FPOFLOW, NULL))) {
265 return ((s.value[0] & QUAD_REAL_M_SIGN) ? QUAD_REAL_MINF : QUAD_REAL_PINF);
266 } else {
267 *p += m;
268 return s;
269 }
270 } else { // s is zero or +-Inf
271 return s;
272 }
273 }
274
275 //! @brief sfmod_quad_real
276
277 QUAD_T sfmod_quad_real (QUAD_T s, int *p)
278 {
279 unt_2 *pa = (unt_2 *) &QV (s);
280 unt_2 *pb = pa + 1;
281 int_2 e, k;
282 e = (*pa & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS;
283 if ((sigerr_quad_real (e >= 15, QUAD_REAL_FPOFLOW, NULL))) {
284 *p = -1;
285 return s;
286 } else if (e < 0) {
287 *p = 0;
288 return s;
289 }
290 *p = *pb >> (15 - e);
291 lshift_quad_real (++e, pb, FLT256_LEN);
292 *pa -= e;
293 for (e = 0; *pb == 0 && e < QUAD_REAL_MAX_P; ++pb, e += 16);
294 if (e == QUAD_REAL_MAX_P) {
295 return QUAD_REAL_ZERO;
296 }
297 for (k = 0; !((*pb << k) & QUAD_REAL_M_SIGN); ++k);
298 if ((k += e)) {
299 lshift_quad_real (k, pa + 1, FLT256_LEN);
300 *pa -= k;
301 }
302 return s;
303 }
304
305 //! @brief lshift_quad_real
306
307 void lshift_quad_real (int n, unt_2 *pm, int m)
308 {
309 unt_2 *pc = pm + m - 1;
310 if (n < 16 * m) {
311 unt_2 *pa = pm + n / 16;
312 m = n % 16;
313 n = 16 - m;
314 while (pa < pc) {
315 *pm = (*pa++) << m;
316 *pm++ |= *pa >> n;
317 }
318 *pm++ = *pa << m;
319 }
320 while (pm <= pc) {
321 *pm++ = 0;
322 }
323 }
324
325 //! @brief rshift_quad_real
326
327 void rshift_quad_real (int n, unt_2 *pm, int m)
328 {
329 unt_2 *pc = pm + m - 1;
330 if (n < 16 * m) {
331 unt_2 *pa = pc - n / 16;
332 m = n % 16;
333 n = 16 - m;
334 while (pa > pm) {
335 *pc = (*pa--) >> m;
336 *pc-- |= *pa << n;
337 }
338 *pc-- = *pa >> m;
339 }
340 while (pc >= pm) {
341 *pc-- = 0;
342 }
343 }
344
345 //! @brief nint_quad_real
346
347 QUAD_T nint_quad_real (QUAD_T x)
348 {
349 if (getsgn_quad_real (&x) == 0) {
350 return floor_quad_real (add_quad_real (x, QUAD_REAL_HALF, A68_FALSE));
351 } else {
352 return neg_quad_real (floor_quad_real (add_quad_real (QUAD_REAL_HALF, x, A68_TRUE)));
353 }
354 }
355
356 //! @brief aint_quad_real
357
358 QUAD_T aint_quad_real (QUAD_T x)
359 {
360 if (getsgn_quad_real (&x) == 0) {
361 return trunc_quad_real (x);
362 } else {
363 return neg_quad_real (trunc_quad_real (x));
364 }
365 }
366
367 //! @brief max_quad_real_2
368
369 QUAD_T max_quad_real_2 (QUAD_T a, QUAD_T b)
370 {
371 if (ge_quad_real (a, b)) {
372 return a;
373 } else {
374 return b;
375 }
376 }
377
378 //! @brief min_quad_real_2
379
380 QUAD_T min_quad_real_2 (QUAD_T a, QUAD_T b)
381 {
382 if (le_quad_real (a, b)) {
383 return a;
384 } else {
385 return b;
386 }
387 }
388
389 //! @brief mod_quad_real
390
391 QUAD_T mod_quad_real (QUAD_T a, QUAD_T b)
392 {
393 QUAD_T q = div_quad_real (a, b);
394 if (sgn_quad_real (&q) >= 0) {
395 q = floor_quad_real (q);
396 } else {
397 q = neg_quad_real (floor_quad_real (neg_quad_real (q)));
398 }
399 return add_quad_real (a, mul_quad_real (b, q), 1);
400 }
401
402 //! @brief add_quad_real
403
404 QUAD_T add_quad_real (QUAD_T s, QUAD_T t, int f)
405 {
406 REAL32 pe;
407 unt_2 *pc, *pf = pe;
408 unt_2 *pa = (unt_2 *) &QV (s);
409 unt_2 *pb = (unt_2 *) &QV (t);
410 int_2 e = *pa & QUAD_REAL_M_EXP;
411 int_2 k = *pb & QUAD_REAL_M_EXP;
412 if (f != 0) {
413 *pb ^= QUAD_REAL_M_SIGN;
414 }
415 unt_2 u = (*pb ^ *pa) & QUAD_REAL_M_SIGN;
416 f = 0;
417 if (e > k) {
418 if ((k = e - k) >= QUAD_REAL_MAX_P) {
419 return s;
420 }
421 rshift_quad_real (k, pb + 1, FLT256_LEN);
422 } else if (e < k) {
423 if ((e = k - e) >= QUAD_REAL_MAX_P) {
424 return t;
425 }
426 rshift_quad_real (e, pa + 1, FLT256_LEN);
427 e = k;
428 pc = pa;
429 pa = pb;
430 pb = pc;
431 } else if (u != 0) {
432 for (pc = pa, pf = pb; *(++pc) == *(++pf) && f < FLT256_LEN; ++f);
433 if (f >= FLT256_LEN) {
434 return QUAD_REAL_ZERO;
435 }
436 if (*pc < *pf) {
437 pc = pa;
438 pa = pb;
439 pb = pc;
440 }
441 pf = pe + f;
442 }
443 unt_2 h = *pa & QUAD_REAL_M_SIGN;
444 unt n = 0;
445 if (u != 0) {
446 for (pc = pb + FLT256_LEN; pc > pb; --pc) {
447 *pc = ~(*pc);
448 }
449 n = 1L;
450 }
451 for (pc = pe + FLT256_LEN, pa += FLT256_LEN, pb += FLT256_LEN; pc > pf;) {
452 n += *pa;
453 pa--;
454 n += *pb;
455 pb--;
456 *pc = n;
457 pc--;
458 n >>= 16;
459 }
460 if (u != 0) {
461 for (; *(++pc) == 0; ++f);
462 for (k = 0; !((*pc << k) & QUAD_REAL_M_SIGN); ++k);
463 if ((k += 16 * f)) {
464 if ((e -= k) <= 0) {
465 return QUAD_REAL_ZERO;
466 }
467 lshift_quad_real (k, pe + 1, FLT256_LEN);
468 }
469 } else {
470 if (n != 0) {
471 ++e;
472 if ((sigerr_quad_real (e == (short) QUAD_REAL_M_EXP, QUAD_REAL_FPOFLOW, NULL))) {
473 return (!h ? QUAD_REAL_PINF : QUAD_REAL_MINF);
474 }
475 ++pf;
476 rshift_quad_real (1, pf, FLT256_LEN);
477 *pf |= QUAD_REAL_M_SIGN;
478 }
479 }
480 *pe = e;
481 *pe |= h;
482 return *(QUAD_T *) pe;
483 }
484
485 //! @brief mul_quad_real
486
487 QUAD_T mul_quad_real (QUAD_T s, QUAD_T t)
488 {
489 unt_2 pe[FLT256_LEN + 2], *q0, *q1, h;
490 unt_2 *pa, *pb, *pc;
491 unt m, n, p;
492 int_2 e;
493 int_2 k;
494 q0 = (unt_2 *) &QV (s);
495 q1 = (unt_2 *) &QV (t);
496 e = (*q0 & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS;
497 k = (*q1 & QUAD_REAL_M_EXP) + 1;
498 if ((sigerr_quad_real (e > (short) QUAD_REAL_M_EXP - k, QUAD_REAL_FPOFLOW, NULL))) {
499 return (((s.value[0] & QUAD_REAL_M_SIGN) ^ (t.value[0] & QUAD_REAL_M_SIGN)) ? QUAD_REAL_MINF : QUAD_REAL_PINF);
500 }
501 if ((e += k) <= 0) {
502 return QUAD_REAL_ZERO;
503 }
504 h = (*q0 ^ *q1) & QUAD_REAL_M_SIGN;
505 for (++q1, k = FLT256_LEN, p = n = 0L, pc = pe + FLT256_LEN + 1; k > 0; --k) {
506 for (pa = q0 + k, pb = q1; pa > q0;) {
507 m = *pa--;
508 m *= *pb++;
509 n += (m & 0xffffL);
510 p += (m >> 16);
511 }
512 *pc-- = n;
513 n = p + (n >> 16);
514 p = 0L;
515 }
516 *pc = n;
517 if (!(*pc & QUAD_REAL_M_SIGN)) {
518 --e;
519 if (e <= 0) {
520 return QUAD_REAL_ZERO;
521 }
522 lshift_quad_real (1, pc, FLT256_LEN + 1);
523 }
524 if ((sigerr_quad_real (e == (short) QUAD_REAL_M_EXP, QUAD_REAL_FPOFLOW, NULL))) {
525 return (!h ? QUAD_REAL_PINF : QUAD_REAL_MINF);
526 }
527 *pe = e;
528 *pe |= h;
529 return *(QUAD_T *) pe;
530 }
531
532 //! @brief div_quad_real
533
534 QUAD_T div_quad_real (QUAD_T s, QUAD_T t)
535 {
536 QUAD_T a;
537 unt_2 *pc, e, i;
538 pc = (unt_2 *) &QV (t);
539 e = *pc;
540 *pc = QUAD_REAL_BIAS;
541 if ((sigerr_quad_real (real_cmp_quad_real (&t, &QUAD_REAL_ZERO) == 0, QUAD_REAL_EDIV, "div_quad_real"))) {
542 return QUAD_REAL_ZERO;
543 } else {
544 a = real_to_quad_real (1 / quad_real_to_real (t));
545 *pc = e;
546 pc = (unt_2 *) &QV (a);
547 *pc += QUAD_REAL_BIAS - (e & QUAD_REAL_M_EXP);
548 *pc |= e & QUAD_REAL_M_SIGN;
549 for (i = 0; i < QUAD_REAL_ITT_DIV; ++i) {
550 a = mul_quad_real (a, add_quad_real (QUAD_REAL_TWO, mul_quad_real (a, t), 1));
551 }
552 return mul_quad_real (s, a);
553 }
554 }
555
556 //! @brief exp2_quad_real
557
558 QUAD_T exp2_quad_real (QUAD_T x)
559 {
560 QUAD_T s, d, f;
561 unt_2 *pf = (unt_2 *) &QV (x);
562 int m, k;
563 if (real_cmp_quad_real (&x, &QUAD_REAL_E2MIN) < 0) {
564 return QUAD_REAL_ZERO;
565 } else if ((sigerr_quad_real (real_cmp_quad_real (&x, &QUAD_REAL_E2MAX) > 0, QUAD_REAL_FPOFLOW, NULL))) {
566 return QUAD_REAL_PINF;
567 } else {
568 m = (*pf & QUAD_REAL_M_SIGN) ? 1 : 0;
569 x = sfmod_quad_real (x, &k);
570 if (m != 0) {
571 k *= -1;
572 }
573 // -QUAD_REAL_BIAS <= k <= +QUAD_REAL_BIAS
574 x = mul_quad_real (x, QUAD_REAL_LN2);
575 if (getexp_quad_real (&x) > -QUAD_REAL_BIAS) {
576 x = real_2_quad_real (x, -1);
577 s = mul_quad_real (x, x);
578 f = QUAD_REAL_ZERO;
579 for (d = int_to_quad_real (m = QUAD_REAL_MS_EXP); m > 1; m -= 2, d = int_to_quad_real (m)) {
580 f = div_quad_real (s, _add_quad_real_ (d, f));
581 }
582 f = div_quad_real (x, _add_quad_real_ (d, f));
583 f = div_quad_real (_add_quad_real_ (d, f), _sub_quad_real_ (d, f));
584 } else {
585 f = QUAD_REAL_ONE;
586 }
587 pf = (unt_2 *) &QV (f);
588 if (-k > *pf) {
589 return QUAD_REAL_ZERO;
590 } else {
591 *pf += k;
592 if ((sigerr_quad_real (*pf >= QUAD_REAL_M_EXP, QUAD_REAL_FPOFLOW, NULL))) {
593 return QUAD_REAL_PINF;
594 } else {
595 return f;
596 }
597 }
598 }
599 }
600
601 //! @brief exp_quad_real
602
603 QUAD_T exp_quad_real (QUAD_T z)
604 {
605 return exp2_quad_real (mul_quad_real (z, QUAD_REAL_LOG2_E));
606 }
607
608 //! @brief exp10_quad_real
609
610 QUAD_T exp10_quad_real (QUAD_T z)
611 {
612 return exp2_quad_real (mul_quad_real (z, QUAD_REAL_LOG2_10));
613 }
614
615 //! @brief fmod_quad_real
616
617 QUAD_T fmod_quad_real (QUAD_T s, QUAD_T t, QUAD_T * q)
618 {
619 if ((sigerr_quad_real (real_cmp_quad_real (&t, &QUAD_REAL_ZERO) == 0, QUAD_REAL_EDIV, "fmod_quad_real"))) {
620 return QUAD_REAL_ZERO;
621 } else {
622 unt_2 *p, mask = 0xffff;
623 int_2 e, i;
624 int u;
625 *q = div_quad_real (s, t);
626 p = (unt_2 *) &(q->value);
627 u = (*p & QUAD_REAL_M_SIGN) ? 0 : 1;
628 e = (*p &= QUAD_REAL_M_EXP); // biased exponent of *q
629 e = e < QUAD_REAL_BIAS ? 0 : e - QUAD_REAL_BIAS + 1;
630 for (i = 1; e / 16 > 0; i++, e -= 16);
631 if (i <= FLT256_LEN) {
632 // e = 0, ..., 15
633 mask <<= 16 - e;
634 p[i] &= mask;
635 for (i++; i <= FLT256_LEN; p[i] = 0, i++);
636 }
637 // Now *q == abs(quotient of (s/t))
638 return add_quad_real (s, mul_quad_real (t, *q), u);
639 }
640 }
641
642 //! @brief frexp_quad_real
643
644 QUAD_T frexp_quad_real (QUAD_T s, int *p)
645 {
646 unt_2 *ps = (unt_2 *) &QV (s), u;
647 *p = (*ps & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS + 1;
648 u = *ps & QUAD_REAL_M_SIGN;
649 *ps = QUAD_REAL_BIAS - 1;
650 *ps |= u;
651 return s;
652 }
653
654 //! @brief nullify
655
656 static void nullify (int skip, unt_2 *p, int k)
657 {
658 // After skipping the first 'skip' bytes of the vector 'p',
659 // this function nullifies all the remaining ones. 'k' is
660 // the number of words forming the vector p.
661 // Warning: 'skip' must be positive !
662 int i;
663 unt_2 mask = 0xffff;
664 for (i = 0; skip / 16 > 0; i++, skip -= 16);
665 if (i < k) {
666 // skip = 0, ..., 15
667 mask <<= 16 - skip;
668 p[i] &= mask;
669 for (i++; i < k; p[i] = 0, i++);
670 }
671 }
672
673 //! @brief canonic_form
674
675 static void canonic_form (QUAD_T * px)
676 {
677 unt_2 *p, u;
678 int_2 e, i, j, skip;
679 p = (unt_2 *) &(px->value);
680 e = (*p & QUAD_REAL_M_EXP); // biased exponent of x
681 u = (*p & QUAD_REAL_M_SIGN); // sign of x
682 if (e < QUAD_REAL_BIAS - 1) {
683 return;
684 } else {
685 unt_2 mask = 0xffff;
686 // e >= QUAD_REAL_BIAS - 1
687 for (i = 1, skip = e + 1 - QUAD_REAL_BIAS; skip / 16 > 0; i++, skip -= 16);
688 if (i <= FLT256_LEN) {
689 // skip = 0, ..., 15
690 mask >>= skip;
691 if ((p[i] & mask) != mask) {
692 return;
693 } else {
694 for (j = i + 1; j <= FLT256_LEN && p[j] == 0xffff; j++);
695 if (j > FLT256_LEN) {
696 p[i] -= mask;
697 for (j = i + 1; j <= FLT256_LEN; p[j] = 0, j++);
698 if (!(p[1] & 0x8000)) {
699 p[1] = 0x8000;
700 *p = ++e;
701 *p |= u;
702 } else if (u != 0) {
703 *px = add_quad_real (*px, QUAD_REAL_ONE, 1);
704 } else {
705 *px = add_quad_real (*px, QUAD_REAL_ONE, 0);
706 }
707 }
708 }
709 }
710 }
711 }
712
713 //! @brief frac_quad_real
714
715 QUAD_T frac_quad_real (QUAD_T x)
716 {
717 // frac_quad_real(x) returns the fractional part of the number x.
718 // frac_quad_real(x) has the same sign as x.
719 unt_2 u, *p;
720 int_2 e;
721 int n;
722 canonic_form (&x);
723 p = (unt_2 *) &QV (x);
724 e = (*p & QUAD_REAL_M_EXP); // biased exponent of x
725 if (e < QUAD_REAL_BIAS) {
726 return x; // The integer part of x is zero
727 } else {
728 u = *p & QUAD_REAL_M_SIGN; // sign of x
729 n = e - QUAD_REAL_BIAS + 1;
730 lshift_quad_real (n, p + 1, FLT256_LEN);
731 e = QUAD_REAL_BIAS - 1;
732 // Now I have to take in account the rule
733 // of the leading one.
734 while (e > 0 && !(p[1] & QUAD_REAL_M_SIGN)) {
735 lshift_quad_real (1, p + 1, FLT256_LEN);
736 e -= 1;
737 }
738 // Now p+1 points to the fractionary part of x,
739 // u is its sign, e is its biased exponent.
740 p[0] = e;
741 p[0] |= u;
742 return *(QUAD_T *) p;
743 }
744 }
745
746 //! @brief trunc_quad_real
747
748 QUAD_T trunc_quad_real (QUAD_T x)
749 {
750 // trunc_quad_real(x) returns the integer part of the number x.
751 // trunc_quad_real(x) has the same sign as x.
752 unt_2 *p;
753 int_2 e;
754 canonic_form (&x);
755 p = (unt_2 *) &QV (x);
756 e = (*p & QUAD_REAL_M_EXP); // biased exponent of x
757 if (e < QUAD_REAL_BIAS) {
758 return QUAD_REAL_ZERO; // The integer part of x is zero
759 } else {
760 nullify (e - QUAD_REAL_BIAS + 1, p + 1, FLT256_LEN);
761 return *(QUAD_T *) p;
762 }
763 }
764
765 //! @brief round_quad_real
766
767 QUAD_T round_quad_real (QUAD_T x)
768 {
769 return trunc_quad_real (add_quad_real (x, QUAD_REAL_RNDCORR, x.value[0] & QUAD_REAL_M_SIGN));
770 }
771
772 //! @brief ceil_quad_real
773
774 QUAD_T ceil_quad_real (QUAD_T x)
775 {
776 unt_2 *ps = (unt_2 *) &QV (x);
777 if ((*ps & QUAD_REAL_M_SIGN)) {
778 return trunc_quad_real (x);
779 } else {
780 QUAD_T y = frac_quad_real (x);
781 // y has the same sign as x (see above).
782 return (real_cmp_quad_real (&y, &QUAD_REAL_ZERO) > 0 ? add_quad_real (trunc_quad_real (x), QUAD_REAL_ONE, 0) : x);
783 }
784 }
785
786 //! @brief floor_quad_real
787
788 QUAD_T floor_quad_real (QUAD_T x)
789 {
790 unt_2 *ps = (unt_2 *) &QV (x);
791 if ((*ps & QUAD_REAL_M_SIGN)) {
792 QUAD_T y = frac_quad_real (x);
793 // y has the same sign as x (see above).
794 return (real_cmp_quad_real (&y, &QUAD_REAL_ZERO) < 0 ? add_quad_real (trunc_quad_real (x), QUAD_REAL_ONE, 1) : x);
795 } else {
796 return trunc_quad_real (x);
797 }
798 }
799
800 //! @brief add_correction_quad_real
801
802 static void add_correction_quad_real (QUAD_T * px, int k)
803 {
804 int_2 e = (px->value[0] & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS;
805 // e = (e > 0 ? e : 0);
806 *px = add_quad_real (*px, real_2_quad_real (QUAD_REAL_FIXCORR, e), k);
807 }
808
809 //! @brief fix_quad_real
810
811 QUAD_T fix_quad_real (QUAD_T x)
812 {
813 unt_2 *p;
814 int_2 e;
815 add_correction_quad_real (&x, x.value[0] & QUAD_REAL_M_SIGN);
816 p = (unt_2 *) &QV (x);
817 e = (*p & QUAD_REAL_M_EXP); // biased exponent of x
818 if (e < QUAD_REAL_BIAS) {
819 return QUAD_REAL_ZERO; // The integer part of x is zero
820 } else {
821 nullify (e - QUAD_REAL_BIAS + 1, p + 1, FLT256_LEN);
822 return *(QUAD_T *) p;
823 }
824 }
825
826 //! @brief tanh_quad_real
827
828 QUAD_T tanh_quad_real (QUAD_T z)
829 {
830 QUAD_T s, d, f;
831 int m, k;
832 if ((k = getexp_quad_real (&z)) > QUAD_REAL_K_TANH) {
833 if (getsgn_quad_real (&z)) {
834 return neg_quad_real (QUAD_REAL_ONE);
835 } else {
836 return QUAD_REAL_ONE;
837 }
838 }
839 if (k < QUAD_REAL_K_LIN) {
840 return z;
841 }
842 ++k;
843 if (k > 0) {
844 z = real_2_quad_real (z, -k);
845 }
846 s = mul_quad_real (z, z);
847 f = QUAD_REAL_ZERO;
848 for (d = int_to_quad_real (m = QUAD_REAL_MS_HYP); m > 1;) {
849 f = div_quad_real (s, _add_quad_real_ (d, f));
850 d = int_to_quad_real (m -= 2);
851 }
852 f = div_quad_real (z, _add_quad_real_ (d, f));
853 for (; k > 0; --k) {
854 f = div_quad_real (real_2_quad_real (f, 1), add_quad_real (d, mul_quad_real (f, f), 0));
855 }
856 return f;
857 }
858
859 //! @brief sinh_quad_real
860
861 QUAD_T sinh_quad_real (QUAD_T z)
862 {
863 int k;
864 if ((k = getexp_quad_real (&z)) < QUAD_REAL_K_LIN) {
865 return z;
866 } else if (k < 0) {
867 z = tanh_quad_real (real_2_quad_real (z, -1));
868 return div_quad_real (real_2_quad_real (z, 1), add_quad_real (QUAD_REAL_ONE, mul_quad_real (z, z), 1));
869 } else {
870 z = exp_quad_real (z);
871 return real_2_quad_real (add_quad_real (z, div_quad_real (QUAD_REAL_ONE, z), 1), -1);
872 }
873 }
874
875 //! @brief cosh_quad_real
876
877 QUAD_T cosh_quad_real (QUAD_T z)
878 {
879 if (getexp_quad_real (&z) < QUAD_REAL_K_LIN) {
880 return QUAD_REAL_ONE;
881 }
882 z = exp_quad_real (z);
883 return real_2_quad_real (add_quad_real (z, div_quad_real (QUAD_REAL_ONE, z), 0), -1);
884 }
885
886 //! @brief atanh_quad_real
887
888 QUAD_T atanh_quad_real (QUAD_T x)
889 {
890 QUAD_T y = x;
891 y.value[0] &= QUAD_REAL_M_EXP; // Now y == abs(x)
892 if ((sigerr_quad_real (real_cmp_quad_real (&y, &QUAD_REAL_ONE) >= 0, QUAD_REAL_EDOM, "xatanh"))) {
893 return ((x.value[0] & QUAD_REAL_M_SIGN) ? QUAD_REAL_MINF : QUAD_REAL_PINF);
894 } else {
895 y = div_quad_real (add_quad_real (QUAD_REAL_ONE, x, 0), add_quad_real (QUAD_REAL_ONE, x, 1));
896 return real_2_quad_real (log_quad_real (y), -1);
897 }
898 }
899
900 //! @brief asinh_quad_real
901
902 QUAD_T asinh_quad_real (QUAD_T x)
903 {
904 QUAD_T y = mul_quad_real (x, x);
905 y = sqrt_quad_real (add_quad_real (QUAD_REAL_ONE, y, 0));
906 if ((x.value[0] & QUAD_REAL_M_SIGN)) {
907 return neg_quad_real (log_quad_real (_sub_quad_real_ (y, x)));
908 } else {
909 return log_quad_real (_add_quad_real_ (x, y));
910 }
911 }
912
913 //! @brief acosh_quad_real
914
915 QUAD_T acosh_quad_real (QUAD_T x)
916 {
917 if ((sigerr_quad_real (real_cmp_quad_real (&x, &QUAD_REAL_ONE) < 0, QUAD_REAL_EDOM, "acosh_quad_real"))) {
918 return QUAD_REAL_ZERO;
919 } else {
920 QUAD_T y = mul_quad_real (x, x);
921 y = sqrt_quad_real (add_quad_real (y, QUAD_REAL_ONE, 1));
922 return log_quad_real (_add_quad_real_ (x, y));
923 }
924 }
925
926 //! @brief atan_quad_real
927
928 QUAD_T atan_quad_real (QUAD_T z)
929 {
930 QUAD_T s, f;
931 int k, m;
932 if ((k = getexp_quad_real (&z)) < QUAD_REAL_K_LIN) {
933 return z;
934 }
935 if (k >= 0) {
936 // k>=0 is equivalent to abs(z) >= 1.0
937 z = div_quad_real (QUAD_REAL_ONE, z);
938 m = 1;
939 } else {
940 m = 0;
941 }
942 f = real_to_quad_real (atan (quad_real_to_real (z)));
943 s = add_quad_real (QUAD_REAL_ONE, mul_quad_real (z, z), 0);
944 for (k = 0; k < QUAD_REAL_ITT_DIV; ++k) {
945 f = add_quad_real (f, div_quad_real (add_quad_real (z, tan_quad_real (f), 1), s), 0);
946 }
947 if (m != 0) {
948 if (getsgn_quad_real (&f)) {
949 return add_quad_real (neg_quad_real (QUAD_REAL_PI2), f, 1);
950 } else {
951 return add_quad_real (QUAD_REAL_PI2, f, 1);
952 }
953 } else {
954 return f;
955 }
956 }
957
958 //! @brief asin_quad_real
959
960 QUAD_T asin_quad_real (QUAD_T z)
961 {
962 QUAD_T u = z;
963 u.value[0] &= QUAD_REAL_M_EXP;
964 if ((sigerr_quad_real (real_cmp_quad_real (&u, &QUAD_REAL_ONE) > 0, QUAD_REAL_EDOM, "asin_quad_real"))) {
965 return ((getsgn_quad_real (&z)) ? neg_quad_real (QUAD_REAL_PI2) : QUAD_REAL_PI2);
966 } else {
967 if (getexp_quad_real (&z) < QUAD_REAL_K_LIN) {
968 return z;
969 }
970 u = sqrt_quad_real (add_quad_real (QUAD_REAL_ONE, mul_quad_real (z, z), 1));
971 if (getexp_quad_real (&u) == -QUAD_REAL_BIAS) {
972 return ((getsgn_quad_real (&z)) ? neg_quad_real (QUAD_REAL_PI2) : QUAD_REAL_PI2);
973 }
974 return atan_quad_real (div_quad_real (z, u));
975 }
976 }
977
978 //! @brief acos_quad_real
979
980 QUAD_T acos_quad_real (QUAD_T z)
981 {
982 QUAD_T u = z;
983 u.value[0] &= QUAD_REAL_M_EXP;
984 if ((sigerr_quad_real (real_cmp_quad_real (&u, &QUAD_REAL_ONE) > 0, QUAD_REAL_EDOM, "acos_quad_real"))) {
985 return ((getsgn_quad_real (&z)) ? QUAD_REAL_PI : QUAD_REAL_ZERO);
986 } else {
987 if (getexp_quad_real (&z) == -QUAD_REAL_BIAS) {
988 return QUAD_REAL_PI2;
989 }
990 u = sqrt_quad_real (add_quad_real (QUAD_REAL_ONE, mul_quad_real (z, z), 1));
991 u = atan_quad_real (div_quad_real (u, z));
992 if (getsgn_quad_real (&z)) {
993 return add_quad_real (QUAD_REAL_PI, u, 0);
994 } else {
995 return u;
996 }
997 }
998 }
999
1000 //! @brief atan2_quad_real
1001
1002 QUAD_T atan2_quad_real (QUAD_T y, QUAD_T x)
1003 {
1004 int rs, is;
1005 rs = sgn_quad_real (&x);
1006 is = sgn_quad_real (&y);
1007 if (rs > 0) {
1008 return atan_quad_real (div_quad_real (y, x));
1009 } else if (rs < 0) {
1010 x.value[0] ^= QUAD_REAL_M_SIGN;
1011 y.value[0] ^= QUAD_REAL_M_SIGN;
1012 if (is >= 0) {
1013 return add_quad_real (QUAD_REAL_PI, atan_quad_real (div_quad_real (y, x)), 0);
1014 } else {
1015 return add_quad_real (atan_quad_real (div_quad_real (y, x)), QUAD_REAL_PI, 1);
1016 }
1017 } else { // x is zero !
1018 if (!sigerr_quad_real (is == 0, QUAD_REAL_EDOM, "atan2_quad_real")) {
1019 return (is > 0 ? QUAD_REAL_PI2 : neg_quad_real (QUAD_REAL_PI2));
1020 } else {
1021 return QUAD_REAL_ZERO; // Dummy value :)
1022 }
1023 }
1024 }
1025
1026 //! @brief log_quad_real
1027
1028 QUAD_T log_quad_real (QUAD_T z)
1029 {
1030 QUAD_T f, h;
1031 int k, m;
1032 if ((sigerr_quad_real ((getsgn_quad_real (&z)) || getexp_quad_real (&z) == -QUAD_REAL_BIAS, QUAD_REAL_EDOM, "log_quad_real"))) {
1033 return QUAD_REAL_MINF;
1034 } else if (real_cmp_quad_real (&z, &QUAD_REAL_ONE) == 0) {
1035 return QUAD_REAL_ZERO;
1036 } else {
1037 z = frexp_quad_real (z, &m);
1038 z = mul_quad_real (z, QUAD_REAL_SQRT2);
1039 z = div_quad_real (add_quad_real (z, QUAD_REAL_ONE, 1), add_quad_real (z, QUAD_REAL_ONE, 0));
1040 h = real_2_quad_real (z, 1);
1041 z = mul_quad_real (z, z);
1042 for (f = h, k = 1; getexp_quad_real (&h) > -QUAD_REAL_MAX_P;) {
1043 h = mul_quad_real (h, z);
1044 f = add_quad_real (f, div_quad_real (h, int_to_quad_real (k += 2)), 0);
1045 }
1046 return add_quad_real (f, mul_quad_real (QUAD_REAL_LN2, real_to_quad_real (m - .5)), 0);
1047 }
1048 }
1049
1050 //! @brief log2_quad_real
1051
1052 QUAD_T log2_quad_real (QUAD_T z)
1053 {
1054 QUAD_T f, h;
1055 int k, m;
1056 if ((sigerr_quad_real ((getsgn_quad_real (&z)) || getexp_quad_real (&z) == -QUAD_REAL_BIAS, QUAD_REAL_EDOM, "log2_quad_real"))) {
1057 return QUAD_REAL_MINF;
1058 } else if (real_cmp_quad_real (&z, &QUAD_REAL_ONE) == 0) {
1059 return QUAD_REAL_ZERO;
1060 } else {
1061 z = frexp_quad_real (z, &m);
1062 z = mul_quad_real (z, QUAD_REAL_SQRT2);
1063 z = div_quad_real (add_quad_real (z, QUAD_REAL_ONE, 1), add_quad_real (z, QUAD_REAL_ONE, 0));
1064 h = real_2_quad_real (z, 1);
1065 z = mul_quad_real (z, z);
1066 for (f = h, k = 1; getexp_quad_real (&h) > -QUAD_REAL_MAX_P;) {
1067 h = mul_quad_real (h, z);
1068 f = add_quad_real (f, div_quad_real (h, int_to_quad_real (k += 2)), 0);
1069 }
1070 return add_quad_real (mul_quad_real (f, QUAD_REAL_LOG2_E), real_to_quad_real (m - .5), 0);
1071 }
1072 }
1073
1074 //! @brief log10_quad_real
1075
1076 QUAD_T log10_quad_real (QUAD_T z)
1077 {
1078 QUAD_T w = log_quad_real (z);
1079 if (real_cmp_quad_real (&w, &QUAD_REAL_MINF) <= 0) {
1080 return QUAD_REAL_MINF;
1081 } else {
1082 return mul_quad_real (w, QUAD_REAL_LOG10_E);
1083 }
1084 }
1085 //! @brief eq_quad_real
1086
1087 int eq_quad_real (QUAD_T x1, QUAD_T x2)
1088 {
1089 return (real_cmp_quad_real (&x1, &x2) == 0);
1090 }
1091
1092 //! @brief neq_quad_real
1093
1094 int neq_quad_real (QUAD_T x1, QUAD_T x2)
1095 {
1096 return (real_cmp_quad_real (&x1, &x2) != 0);
1097 }
1098
1099 //! @brief gt_quad_real
1100
1101 int gt_quad_real (QUAD_T x1, QUAD_T x2)
1102 {
1103 return (real_cmp_quad_real (&x1, &x2) > 0);
1104 }
1105
1106 //! @brief ge_quad_real
1107
1108 int ge_quad_real (QUAD_T x1, QUAD_T x2)
1109 {
1110 return (real_cmp_quad_real (&x1, &x2) >= 0);
1111 }
1112
1113 //! @brief lt_quad_real
1114
1115 int lt_quad_real (QUAD_T x1, QUAD_T x2)
1116 {
1117 return (real_cmp_quad_real (&x1, &x2) < 0);
1118 }
1119
1120 //! @brief le_quad_real
1121
1122 int le_quad_real (QUAD_T x1, QUAD_T x2)
1123 {
1124 return (real_cmp_quad_real (&x1, &x2) <= 0);
1125 }
1126 // isNaN_quad_real (&x) returns 1 if and only if x is not a valid number
1127
1128 int isNaN_quad_real (const QUAD_T * u)
1129 {
1130 unt_2 *p = (unt_2 *) &(u->value);
1131 if (*p != 0) {
1132 return 0;
1133 } else {
1134 int i;
1135 for (i = 1; i <= FLT256_LEN && p[i] == 0x0; i++);
1136 return (i <= FLT256_LEN ? 1 : 0);
1137 }
1138 }
1139
1140 //! @brief is0_quad_real
1141
1142 int is0_quad_real (const QUAD_T * u)
1143 {
1144 unt_2 *p = (unt_2 *) &(u->value);
1145 int m;
1146 for (m = 1; m <= FLT256_LEN && p[m] == 0; m++);
1147 return (m > FLT256_LEN && (*p & QUAD_REAL_M_EXP) < QUAD_REAL_M_EXP ? 1 : 0);
1148 }
1149
1150 //! @brief not0_quad_real
1151
1152 int not0_quad_real (const QUAD_T * u)
1153 {
1154 unt_2 *p = (unt_2 *) &(u->value);
1155 int m;
1156 for (m = 1; m <= FLT256_LEN && p[m] == 0; m++);
1157 return (m > FLT256_LEN && (*p & QUAD_REAL_M_EXP) < QUAD_REAL_M_EXP ? 0 : 1);
1158 }
1159
1160 //! @brief sgn_quad_real
1161
1162 int sgn_quad_real (const QUAD_T * u)
1163 {
1164 unt_2 *p = (unt_2 *) &(u->value);
1165 int m;
1166 for (m = 1; m <= FLT256_LEN && p[m] == 0; m++);
1167 if ((m > FLT256_LEN && (*p & QUAD_REAL_M_EXP) < QUAD_REAL_M_EXP) || !*p) {
1168 return 0;
1169 } else {
1170 return ((*p & QUAD_REAL_M_SIGN) ? -1 : 1);
1171 }
1172 }
1173
1174 //! @brief isPinf_quad_real
1175
1176 int isPinf_quad_real (const QUAD_T * u)
1177 {
1178 return (*u->value == QUAD_REAL_M_EXP ? 1 : 0);
1179 }
1180
1181 //! @brief isMinf_quad_real
1182
1183 int isMinf_quad_real (const QUAD_T * u)
1184 {
1185 return (*u->value == (QUAD_REAL_M_EXP | QUAD_REAL_M_SIGN) ? 1 : 0);
1186 }
1187
1188 //! @brief isordnumb_quad_real
1189
1190 int isordnumb_quad_real (const QUAD_T * u)
1191 {
1192 int isNaN, isfinite;
1193 unt_2 *p = (unt_2 *) &(u->value);
1194 if (*p != 0) {
1195 isNaN = 0;
1196 } else {
1197 int i;
1198 for (i = 1; i <= FLT256_LEN && p[i] == 0x0; i++);
1199 isNaN = i <= FLT256_LEN;
1200 }
1201 isfinite = (*p & QUAD_REAL_M_EXP) < QUAD_REAL_M_EXP;
1202 return (!isNaN && (isfinite) ? 1 : 0);
1203 }
1204
1205 //! @brief pwr_quad_real
1206
1207 QUAD_T pwr_quad_real (QUAD_T s, int n)
1208 {
1209 QUAD_T t;
1210 unsigned k, m;
1211 t = QUAD_REAL_ONE;
1212 if (n < 0) {
1213 m = -n;
1214 if ((sigerr_quad_real (real_cmp_quad_real (&s, &QUAD_REAL_ZERO) == 0, QUAD_REAL_EBADEXP, "pwr_quad_real"))) {
1215 return QUAD_REAL_ZERO;
1216 }
1217 s = div_quad_real (QUAD_REAL_ONE, s);
1218 } else {
1219 m = n;
1220 }
1221 if (m != 0) {
1222 k = 1;
1223 while (1) {
1224 if (k & m) {
1225 t = mul_quad_real (s, t);
1226 }
1227 if ((k <<= 1) <= m) {
1228 s = mul_quad_real (s, s);
1229 } else {
1230 break;
1231 }
1232 }
1233 } else {
1234 sigerr_quad_real (real_cmp_quad_real (&s, &QUAD_REAL_ZERO) == 0, QUAD_REAL_EBADEXP, "pwr_quad_real");
1235 }
1236 return t;
1237 }
1238
1239 //! @brief pow_quad_real
1240
1241 QUAD_T pow_quad_real (QUAD_T x, QUAD_T y)
1242 {
1243 if (sigerr_quad_real ((getsgn_quad_real (&x)) || getexp_quad_real (&x) == -QUAD_REAL_BIAS, QUAD_REAL_EDOM, "pow_quad_real")) {
1244 return QUAD_REAL_ZERO;
1245 } else {
1246 return exp2_quad_real (mul_quad_real (log2_quad_real (x), y));
1247 }
1248 }
1249
1250 //! @brief sqrt_quad_real
1251
1252 QUAD_T sqrt_quad_real (QUAD_T z)
1253 {
1254 if ((sigerr_quad_real ((getsgn_quad_real (&z)), QUAD_REAL_EDOM, "sqrt_quad_real"))) {
1255 return QUAD_REAL_ZERO;
1256 } else {
1257 unt_2 *pc = (unt_2 *) &QV (z);
1258 if (*pc == 0) {
1259 return QUAD_REAL_ZERO;
1260 }
1261 int_2 e = *pc - QUAD_REAL_BIAS;
1262 *pc = QUAD_REAL_BIAS + (e % 2);
1263 e /= 2;
1264 QUAD_T h, s = real_to_quad_real (sqrt (quad_real_to_real (z)));
1265 for (int_2 m = 0; m < QUAD_REAL_ITT_DIV; ++m) {
1266 h = div_quad_real (add_quad_real (z, mul_quad_real (s, s), 1), real_2_quad_real (s, 1));
1267 s = _add_quad_real_ (s, h);
1268 }
1269 pc = (unt_2 *) &QV (s);
1270 *pc += e;
1271 return s;
1272 }
1273 }
1274
1275 static int odd_quad_real (QUAD_T x)
1276 {
1277 unt_2 *p = (unt_2 *) &QV (x);
1278 int_2 e, i;
1279 e = (*p & QUAD_REAL_M_EXP) - QUAD_REAL_BIAS; // exponent of x
1280 if (e < 0) {
1281 return 0;
1282 } else {
1283 for (i = 1; e / 16 > 0; i++, e -= 16);
1284 // Now e = 0, ..., 15
1285 return (i <= FLT256_LEN ? p[i] & 0x8000 >> e : 0);
1286 }
1287 }
1288
1289 //! @brief tan_quad_real
1290
1291 QUAD_T tan_quad_real (QUAD_T z)
1292 {
1293 int k, m;
1294 z = rred (z, 't', &k);
1295 if ((sigerr_quad_real (real_cmp_quad_real (&z, &QUAD_REAL_PI2) >= 0, QUAD_REAL_EDOM, "tan_quad_real"))) {
1296 return (!k ? QUAD_REAL_PINF : QUAD_REAL_MINF);
1297 } else {
1298 if (real_cmp_quad_real (&z, &QUAD_REAL_PI4) == 1) {
1299 m = 1;
1300 z = add_quad_real (QUAD_REAL_PI2, z, 1);
1301 } else {
1302 m = 0;
1303 }
1304 if (k != 0) {
1305 z = neg_quad_real (c_tan (z));
1306 } else {
1307 z = c_tan (z);
1308 }
1309 if (m != 0) {
1310 return div_quad_real (QUAD_REAL_ONE, z);
1311 } else {
1312 return z;
1313 }
1314 }
1315 }
1316
1317 //! @brief cos_quad_real
1318
1319 QUAD_T cos_quad_real (QUAD_T z)
1320 {
1321 int k;
1322 z = rred (z, 'c', &k);
1323 if (getexp_quad_real (&z) < QUAD_REAL_K_LIN) {
1324 if (k != 0) {
1325 return neg_quad_real (QUAD_REAL_ONE);
1326 } else {
1327 return QUAD_REAL_ONE;
1328 }
1329 }
1330 z = c_tan (real_2_quad_real (z, -1));
1331 z = mul_quad_real (z, z);
1332 z = div_quad_real (add_quad_real (QUAD_REAL_ONE, z, 1), add_quad_real (QUAD_REAL_ONE, z, 0));
1333 if (k != 0) {
1334 return neg_quad_real (z);
1335 } else {
1336 return z;
1337 }
1338 }
1339
1340 //! @brief sin_quad_real
1341
1342 QUAD_T sin_quad_real (QUAD_T z)
1343 {
1344 int k;
1345 z = rred (z, 's', &k);
1346 if (getexp_quad_real (&z) >= QUAD_REAL_K_LIN) {
1347 z = c_tan (real_2_quad_real (z, -1));
1348 z = div_quad_real (real_2_quad_real (z, 1), add_quad_real (QUAD_REAL_ONE, mul_quad_real (z, z), 0));
1349 }
1350 if (k != 0) {
1351 return neg_quad_real (z);
1352 } else {
1353 return z;
1354 }
1355 }
1356
1357 static QUAD_T c_tan (QUAD_T z)
1358 {
1359 QUAD_T s, f, d;
1360 int m;
1361 unt_2 k;
1362 if (getexp_quad_real (&z) < QUAD_REAL_K_LIN)
1363 return z;
1364 s = neg_quad_real (mul_quad_real (z, z));
1365 for (k = 1; k <= FLT256_LEN && s.value[k] == 0; k++);
1366 if ((sigerr_quad_real (s.value[0] == 0xffff && k > FLT256_LEN, QUAD_REAL_FPOFLOW, NULL))) {
1367 return QUAD_REAL_ZERO;
1368 } else {
1369 f = QUAD_REAL_ZERO;
1370 for (d = int_to_quad_real (m = QUAD_REAL_MS_TRG); m > 1;) {
1371 f = div_quad_real (s, _add_quad_real_ (d, f));
1372 d = int_to_quad_real (m -= 2);
1373 }
1374 return div_quad_real (z, _add_quad_real_ (d, f));
1375 }
1376 }
1377
1378 static QUAD_T rred (QUAD_T z, int kf, int *ps)
1379 {
1380 QUAD_T is, q;
1381 if (getsgn_quad_real (&z)) {
1382 z = neg_quad_real (z);
1383 is = QUAD_REAL_ONE;
1384 } else {
1385 is = QUAD_REAL_ZERO;
1386 }
1387 z = fmod_quad_real (z, QUAD_REAL_PI, &q);
1388 if (kf == 't') {
1389 q = is;
1390 } else if (kf == 's') {
1391 q = _add_quad_real_ (q, is);
1392 }
1393 if (real_cmp_quad_real (&z, &QUAD_REAL_PI2) == 1) {
1394 z = add_quad_real (QUAD_REAL_PI, z, 1);
1395 if (kf == 'c' || kf == 't') {
1396 q = add_quad_real (q, QUAD_REAL_ONE, 0);
1397 }
1398 }
1399 *ps = (odd_quad_real (q)) ? 1 : 0;
1400 return z;
1401 }
1402
1403 // VIF additions (REAL*32)
1404
1405 //! @brief cotan_quad_real
1406
1407 QUAD_T cotan_quad_real (QUAD_T x)
1408 {
1409 return div_quad_real (QUAD_REAL_ONE, tan_quad_real (x));
1410 }
1411
1412 //! @brief acotan_quad_real
1413
1414 QUAD_T acotan_quad_real (QUAD_T x)
1415 {
1416 return atan_quad_real (div_quad_real (QUAD_REAL_ONE, x));
1417 }
1418
1419 //! @brief sgn_quad_real_2
1420
1421 QUAD_T sgn_quad_real_2 (QUAD_T a, QUAD_T b)
1422 {
1423 QUAD_T x = (getsgn_quad_real (&a) == 0 ? a : neg_quad_real (a));
1424 return (getsgn_quad_real (&b) == 0 ? x : neg_quad_real (x));
1425 }
1426
1427 #endif