1 /**
2 @file mp.c
3 @author J. Marcel van der Veer.
4 @brief Multiprecision arithmetic library.
5 @section Copyright
6
7 This file is part of Algol68G - an Algol 68 compiler-interpreter.
8 Copyright 2001-2016 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 under
13 the terms of the GNU General Public License as published by the Free Software
14 Foundation; either version 3 of the License, or (at your option) any later
15 version.
16
17 This program is distributed in the hope that it will be useful, but WITHOUT ANY
18 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19 PARTICULAR PURPOSE. See the GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program. If not, see <http://www.gnu.org/licenses/>.
23
24 @section Description
25
26 This is a multiprecision arithmetic library for Algol68G.
27
28 The question that is often raised is what applications justify multiprecision
29 calculations. A number of applications, some of them practical, have surfaced
30 over the years.
31
32 Most common application of multiprecision calculations are numerically unstable
33 calculations, that require many significant digits to arrive at a reliable
34 result.
35
36 Multiprecision calculations are used in "experimental mathematics". An
37 increasingly important application of computers is in doing experiments on
38 mathematical systems, when such system is not easily, or not at all, tractable
39 by analysis.
40
41 One important area of applications is in pure mathematics. Although numerical
42 calculations cannot substitute a formal proof, calculations can be used to
43 explore conjectures and reject those that are not sound, before a lengthy
44 attempt at such proof is undertaken.
45
46 Multiprecision calculations are especially useful in the study of mathematical
47 constants. One of the oldest applications of multiprecision computation is to
48 explore whether the expansions of classical constants such as "pi", "e" or
49 "sqrt(2)" are random in some sense. For example, digits of "pi" have not shown
50 statistical anomalies even now that billions of digits have been calculated.
51
52 A practical application of multiprecision computation is the emerging
53 field of public-key cryptography, that has spawned much research into advanced
54 algorithms for factoring large integers.
55
56 An indirect application of multiprecision computation is integrity testing.
57 A unique feature of multiprecision calculations is that they are unforgiving
58 of hardware, program or compiler error. Even a single computational error will
59 almost certainly result in a completely incorrect outcome after a possibly
60 correct start.
61
62 The routines in this library follow algorithms as described in the
63 literature, notably
64
65 D.M. Smith, "Efficient Multiple-Precision Evaluation of Elementary Functions"
66 Mathematics of Computation 52 (1989) 131-134
67
68 D.M. Smith, "A Multiple-Precision Division Algorithm"
69 Mathematics of Computation 66 (1996) 157-163
70
71 There are multiprecision libraries (freely) available, but this one is
72 particularly designed to work with Algol68G. It implements following modes:
73
74 LONG INT, LONG REAL, LONG COMPLEX, LONG BITS
75 LONG LONG INT, LONG LONG REAL, LONG LONG COMPLEX, LONG LONG BITS
76
77 Currently, LONG modes have a fixed precision, and LONG LONG modes have
78 user-definable precision. Precisions span about 30 decimal digits for
79 LONG modes up to (default) about 60 decimal digits for LONG LONG modes, a
80 range that is said to be adequate for most multiprecision applications.
81
82 Although the maximum length of a mp number is unbound, this implementation
83 is not particularly designed for more than about a thousand digits. It will
84 work at higher precisions, but with a performance penalty with respect to
85 state of the art implementations that may for instance use convolution for
86 multiplication.
87
88 This library takes a sloppy approach towards LONG INT and LONG BITS which are
89 implemented as LONG REAL and truncated where appropriate. This keeps the code
90 short at the penalty of some performance loss.
91
92 As is common practice, mp numbers are represented by a row of digits
93 in a large base. Layout of a mp number "z" is:
94
95 MP_T *z;
96 MP_STATUS (z) Status word
97 MP_EXPONENT (z) Exponent with base MP_RADIX
98 MP_DIGIT (z, 1 .. N) Digits 1 .. N
99
100 Note that this library assumes IEEE 754 compatible implementation of
101 type "double". It also assumes 32 (or 64) bit type "int".
102
103 Most "vintage" multiple precision libraries stored numbers as [] int.
104 However, since division and multiplication are O (N ** 2) operations, it is
105 advantageous to keep the base as high as possible. Modern computers handle
106 doubles at similar or better speed as integers, therefore this library
107 opts for storing numbers as [] double, trading space for speed. This may
108 change when 64 bit integers become commonplace.
109
110 Set a base such that "base ** 2" can be exactly represented by "double".
111 To facilitate transput, we require a base that is a power of 10.
112
113 If we choose the base right then in multiplication and division we do not need
114 to normalise intermediate results at each step since a number of additions
115 can be made before overflow occurs. That is why we specify "MAX_REPR_INT".
116
117 Mind that the precision of a mp number is at worst just
118 (LONG_MP_DIGITS - 1) * LOG_MP_BASE + 1, since the most significant mp digit
119 is also in range [0 .. MP_RADIX>. Do not specify less than 2 digits.
120
121 Since this software is distributed without any warranty, it is your
122 responsibility to validate the behaviour of the routines and their accuracy
123 using the source code provided. See the GNU General Public License for details.
124 **/
125
126 #if defined HAVE_CONFIG_H
127 #include "a68g-config.h"
128 #endif
129
130 #include "a68g.h"
131
132 /* If DOUBLE_PRECISION is defined functions are evaluated in double precision */
133
134 #undef DOUBLE_PRECISION
135
136 /* Internal mp constants */
137
138 static MP_T *ref_mp_pi = NO_MP;
139 static int mp_pi_size = -1;
140
141 static MP_T *ref_mp_ln_scale = NO_MP;
142 static int mp_ln_scale_size = -1;
143
144 static MP_T *ref_mp_ln_10 = NO_MP;
145 static int mp_ln_10_size = -1;
146
147 int varying_mp_digits = 10;
148
149 static int _j1_, _j2_;
150 #define MINIMUM(x, y) (_j1_ = (x), _j2_ = (y), _j1_ < _j2_ ? _j1_ : _j2_)
151
152 /*
153 GUARD_DIGITS: number of guard digits.
154
155 In calculations using intermediate results we will use guard digits.
156 We follow D.M. Smith in his recommendations for precisions greater than LONG.
157 */
158
159 #if defined DOUBLE_PRECISION
160 #define GUARD_DIGITS(digits) (digits)
161 #else
162 #define GUARD_DIGITS(digits) (((digits) == LONG_MP_DIGITS) ? 2 : (LOG_MP_BASE <= 5) ? 3 : 2)
163 #endif
164
165 #define FUN_DIGITS(n) ((n) + GUARD_DIGITS (n))
166
167 /**
168 @brief Length in bytes of a long mp number.
169 @return Length in bytes of a long mp number.
170 **/
171
172 size_t
size_long_mp(void)173 size_long_mp (void)
174 {
175 return ((size_t) SIZE_MP (LONG_MP_DIGITS));
176 }
177
178 /**
179 @brief Length in digits of a long mp number.
180 @return Length in digits of a long mp number.
181 **/
182
183 int
long_mp_digits(void)184 long_mp_digits (void)
185 {
186 return (LONG_MP_DIGITS);
187 }
188
189 /**
190 @brief Length in bytes of a long long mp number.
191 @return Length in bytes of a long long mp number.
192 **/
193
194 size_t
size_longlong_mp(void)195 size_longlong_mp (void)
196 {
197 return ((size_t) (SIZE_MP (varying_mp_digits)));
198 }
199
200 /**
201 @brief Length in digits of a long long mp number.
202 @return Length in digits of a long long mp number.
203 **/
204
205 int
longlong_mp_digits(void)206 longlong_mp_digits (void)
207 {
208 return (varying_mp_digits);
209 }
210
211 /**
212 @brief Length in bits of mode.
213 @param m Mode.
214 @return Length in bits of mode m.
215 **/
216
217 int
get_mp_bits_width(MOID_T * m)218 get_mp_bits_width (MOID_T * m)
219 {
220 if (m == MODE (LONG_BITS)) {
221 return (MP_BITS_WIDTH (LONG_MP_DIGITS));
222 } else if (m == MODE (LONGLONG_BITS)) {
223 return (MP_BITS_WIDTH (varying_mp_digits));
224 }
225 return (0);
226 }
227
228 /**
229 @brief Length in words of mode.
230 @param m Mode.
231 @return Length in words of mode m.
232 **/
233
234 int
get_mp_bits_words(MOID_T * m)235 get_mp_bits_words (MOID_T * m)
236 {
237 if (m == MODE (LONG_BITS)) {
238 return (MP_BITS_WORDS (LONG_MP_DIGITS));
239 } else if (m == MODE (LONGLONG_BITS)) {
240 return (MP_BITS_WORDS (varying_mp_digits));
241 }
242 return (0);
243 }
244
245 /**
246 @brief Whether z is a valid LONG INT.
247 @param z Multiprecision number.
248 @return See brief description.
249 **/
250
251 BOOL_T
check_long_int(MP_T * z)252 check_long_int (MP_T * z)
253 {
254 return ((BOOL_T) ((MP_EXPONENT (z) >= (MP_T) 0) && (MP_EXPONENT (z) < (MP_T) LONG_MP_DIGITS)));
255 }
256
257 /**
258 @brief Whether z is a valid LONG LONG INT.
259 @param z Multiprecision number.
260 @return See brief description.
261 **/
262
263 BOOL_T
check_longlong_int(MP_T * z)264 check_longlong_int (MP_T * z)
265 {
266 return ((BOOL_T) ((MP_EXPONENT (z) >= (MP_T) 0) && (MP_EXPONENT (z) < (MP_T) varying_mp_digits)));
267 }
268
269 /**
270 @brief Whether z is a valid representation for its mode.
271 @param z Multiprecision number.
272 @param m Mode.
273 @return See brief description.
274 **/
275
276 BOOL_T
check_mp_int(MP_T * z,MOID_T * m)277 check_mp_int (MP_T * z, MOID_T * m)
278 {
279 if (m == MODE (LONG_INT) || m == MODE (LONG_BITS)) {
280 return (check_long_int (z));
281 } else if (m == MODE (LONGLONG_INT) || m == MODE (LONGLONG_BITS)) {
282 return (check_longlong_int (z));
283 }
284 return (A68_FALSE);
285 }
286
287 /**
288 @brief Convert precision to digits for long long number.
289 @param n Precision to convert.
290 @return See brief description.
291 **/
292
293 int
int_to_mp_digits(int n)294 int_to_mp_digits (int n)
295 {
296 return (2 + (int) ceil ((double) n / (double) LOG_MP_BASE));
297 }
298
299 /**
300 @brief Set number of digits for long long numbers.
301 @param n Number of digits.
302 **/
303
304 void
set_longlong_mp_digits(int n)305 set_longlong_mp_digits (int n)
306 {
307 varying_mp_digits = n;
308 }
309
310 /**
311 @brief Set "z" to short value x * MP_RADIX ** x_expo.
312 @param z Multiprecision number to set.
313 @param x Most significant mp digit.
314 @param x_expo Multiprecision exponent.
315 @param digits Precision in mp-digits.
316 @return Result "z".
317 **/
318
319 MP_T *
set_mp_short(MP_T * z,MP_T x,int x_expo,int digits)320 set_mp_short (MP_T * z, MP_T x, int x_expo, int digits)
321 {
322 MP_T *d = &MP_DIGIT ((z), 2);
323 MP_STATUS (z) = (MP_T) INIT_MASK;
324 MP_EXPONENT (z) = (MP_T) x_expo;
325 MP_DIGIT (z, 1) = (MP_T) x;
326 while (--digits) {
327 *d++ = (MP_T) 0;
328 }
329 return (z);
330 }
331
332 /**
333 @brief Test whether x = y.
334 @param p Node in syntax tree.
335 @param x Multiprecision number 1.
336 @param y Multiprecision number 2.
337 @param digits Precision in mp-digits.
338 @return See brief description.
339 **/
340
341 static BOOL_T
same_mp(NODE_T * p,MP_T * x,MP_T * y,int digits)342 same_mp (NODE_T * p, MP_T * x, MP_T * y, int digits)
343 {
344 int k;
345 (void) p;
346 if (MP_EXPONENT (x) == MP_EXPONENT (y)) {
347 for (k = digits; k >= 1; k--) {
348 if (MP_DIGIT (x, k) != MP_DIGIT (y, k)) {
349 return (A68_FALSE);
350 }
351 }
352 return (A68_TRUE);
353 } else {
354 return (A68_FALSE);
355 }
356 }
357
358 /**
359 @brief Align 10-base z in a MP_RADIX mantissa.
360 @param z Multiprecision number.
361 @param expo
362 @param digits Precision in mp-digits.
363 @return Result "z".
364 **/
365
366 static MP_T *
align_mp(MP_T * z,int * expo,int digits)367 align_mp (MP_T * z, int *expo, int digits)
368 {
369 int i, shift;
370 if (*expo >= 0) {
371 shift = LOG_MP_BASE - *expo % LOG_MP_BASE - 1;
372 *expo /= LOG_MP_BASE;
373 } else {
374 shift = (-*expo - 1) % LOG_MP_BASE;
375 *expo = (*expo + 1) / LOG_MP_BASE;
376 (*expo)--;
377 }
378 /* Now normalise "z" */
379 for (i = 1; i <= shift; i++) {
380 int j, carry = 0;
381 for (j = 1; j <= digits; j++) {
382 int k = (int) MP_DIGIT (z, j) % 10;
383 MP_DIGIT (z, j) = (MP_T) ((int) (MP_DIGIT (z, j) / 10) + carry * (MP_RADIX / 10));
384 carry = k;
385 }
386 }
387 return (z);
388 }
389
390 /**
391 @brief Transform string into multi-precision number.
392 @param p Node in syntax tree.
393 @param z Multiprecision number.
394 @param s String to convert.
395 @param digits Precision in mp-digits.
396 @return Result "z".
397 **/
398
399 MP_T *
string_to_mp(NODE_T * p,MP_T * z,char * s,int digits)400 string_to_mp (NODE_T * p, MP_T * z, char *s, int digits)
401 {
402 int i, j, sign, weight, sum, comma, power;
403 int expo;
404 BOOL_T ok = A68_TRUE;
405 RESET_ERRNO;
406 SET_MP_ZERO (z, digits);
407 while (IS_SPACE (s[0])) {
408 s++;
409 }
410 /* Get the sign */
411 sign = (s[0] == '-' ? -1 : 1);
412 if (s[0] == '+' || s[0] == '-') {
413 s++;
414 }
415 /* Scan mantissa digits and put them into "z" */
416 while (s[0] == '0') {
417 s++;
418 }
419 i = 0;
420 j = 1;
421 sum = 0;
422 comma = -1;
423 power = 0;
424 weight = MP_RADIX / 10;
425 while (s[i] != NULL_CHAR && j <= digits && (IS_DIGIT (s[i]) || s[i] == POINT_CHAR)) {
426 if (s[i] == POINT_CHAR) {
427 comma = i;
428 } else {
429 int value = (int) s[i] - (int) '0';
430 sum += weight * value;
431 weight /= 10;
432 power++;
433 if (weight < 1) {
434 MP_DIGIT (z, j++) = (MP_T) sum;
435 sum = 0;
436 weight = MP_RADIX / 10;
437 }
438 }
439 i++;
440 }
441 /* Store the last digits */
442 if (j <= digits) {
443 MP_DIGIT (z, j++) = (MP_T) sum;
444 }
445 /* See if there is an exponent */
446 expo = 0;
447 if (s[i] != NULL_CHAR && TO_UPPER (s[i]) == TO_UPPER (EXPONENT_CHAR)) {
448 char *end;
449 expo = (int) strtol (&(s[++i]), &end, 10);
450 ok = (BOOL_T) (end[0] == NULL_CHAR);
451 } else {
452 ok = (BOOL_T) (s[i] == NULL_CHAR);
453 }
454 /* Calculate effective exponent */
455 expo += (comma >= 0 ? comma - 1 : power - 1);
456 (void) align_mp (z, &expo, digits);
457 MP_EXPONENT (z) = (MP_DIGIT (z, 1) == 0 ? 0 : (double) expo);
458 MP_DIGIT (z, 1) *= sign;
459 CHECK_MP_EXPONENT (p, z);
460 if (errno == 0 && ok) {
461 return (z);
462 } else {
463 return (NO_MP);
464 }
465 }
466
467 /**
468 @brief Convert integer to multi-precison number.
469 @param p Node in syntax tree.
470 @param z Multiprecision number.
471 @param k Integer to convert.
472 @param digits Precision in mp-digits.
473 @return Result "z".
474 **/
475
476 MP_T *
int_to_mp(NODE_T * p,MP_T * z,int k,int digits)477 int_to_mp (NODE_T * p, MP_T * z, int k, int digits)
478 {
479 int n = 0, j, sign_k = SIGN (k);
480 int k2 = k;
481 if (k < 0) {
482 k = -k;
483 }
484 while ((k2 /= MP_RADIX) != 0) {
485 n++;
486 }
487 SET_MP_ZERO (z, digits);
488 MP_EXPONENT (z) = (MP_T) n;
489 for (j = 1 + n; j >= 1; j--) {
490 MP_DIGIT (z, j) = (MP_T) (k % MP_RADIX);
491 k /= MP_RADIX;
492 }
493 MP_DIGIT (z, 1) = sign_k * MP_DIGIT (z, 1);
494 CHECK_MP_EXPONENT (p, z);
495 return (z);
496 }
497
498 /**
499 @brief Convert unsigned to multi-precison number.
500 @param p Node in syntax tree.
501 @param z Multiprecision number.
502 @param k Unsigned to convert.
503 @param digits Precision in mp-digits.
504 @return Result "z".
505 **/
506
507 MP_T *
unsigned_to_mp(NODE_T * p,MP_T * z,unsigned k,int digits)508 unsigned_to_mp (NODE_T * p, MP_T * z, unsigned k, int digits)
509 {
510 int n = 0, j;
511 unsigned k2 = k;
512 while ((k2 /= MP_RADIX) != 0) {
513 n++;
514 }
515 SET_MP_ZERO (z, digits);
516 MP_EXPONENT (z) = (MP_T) n;
517 for (j = 1 + n; j >= 1; j--) {
518 MP_DIGIT (z, j) = (MP_T) (k % MP_RADIX);
519 k /= MP_RADIX;
520 }
521 CHECK_MP_EXPONENT (p, z);
522 return (z);
523 }
524
525 /**
526 @brief Convert multi-precision number to integer.
527 @param p Node in syntax tree.
528 @param z Multiprecision number.
529 @param digits Precision in mp-digits.
530 @return Result "z".
531 **/
532
533 int
mp_to_int(NODE_T * p,MP_T * z,int digits)534 mp_to_int (NODE_T * p, MP_T * z, int digits)
535 {
536 /*
537 This routines looks a lot like "strtol".
538 We do not use "mp_to_real" since int could be wider than 2 ** 52.
539 */
540 int j, expo = (int) MP_EXPONENT (z);
541 int sum = 0, weight = 1;
542 BOOL_T negative;
543 if (expo >= digits) {
544 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MOID (p));
545 exit_genie (p, A68_RUNTIME_ERROR);
546 }
547 negative = (BOOL_T) (MP_DIGIT (z, 1) < 0);
548 if (negative) {
549 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
550 }
551 for (j = 1 + expo; j >= 1; j--) {
552 int term;
553 if ((int) MP_DIGIT (z, j) > A68_MAX_INT / weight) {
554 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MODE (INT));
555 exit_genie (p, A68_RUNTIME_ERROR);
556 }
557 term = (int) MP_DIGIT (z, j) * weight;
558 if (sum > A68_MAX_INT - term) {
559 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MODE (INT));
560 exit_genie (p, A68_RUNTIME_ERROR);
561 }
562 sum += term;
563 weight *= MP_RADIX;
564 }
565 return (negative ? -sum : sum);
566 }
567
568 /**
569 @brief Convert multi-precision number to unsigned.
570 @param p Node in syntax tree.
571 @param z Multiprecision number.
572 @param digits Precision in mp-digits.
573 @return Result "z".
574 **/
575
576 unsigned
mp_to_unsigned(NODE_T * p,MP_T * z,int digits)577 mp_to_unsigned (NODE_T * p, MP_T * z, int digits)
578 {
579 /*
580 This routines looks a lot like "strtol". We do not use "mp_to_real" since int
581 could be wider than 2 ** 52.
582 */
583 int j, expo = (int) MP_EXPONENT (z);
584 unsigned sum = 0, weight = 1;
585 if (expo >= digits) {
586 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MOID (p));
587 exit_genie (p, A68_RUNTIME_ERROR);
588 }
589 for (j = 1 + expo; j >= 1; j--) {
590 unsigned term;
591 if ((unsigned) MP_DIGIT (z, j) > A68_MAX_UNT / weight) {
592 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MODE (BITS));
593 exit_genie (p, A68_RUNTIME_ERROR);
594 }
595 term = (unsigned) MP_DIGIT (z, j) * weight;
596 if (sum > A68_MAX_UNT - term) {
597 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MODE (BITS));
598 exit_genie (p, A68_RUNTIME_ERROR);
599 }
600 sum += term;
601 weight *= MP_RADIX;
602 }
603 return (sum);
604 }
605
606 /**
607 @brief Convert double to multi-precison number.
608 @param p Node in syntax tree.
609 @param z Multiprecision number.
610 @param x Multiprecision number.
611 @param digits Precision in mp-digits.
612 @return Result "z".
613 **/
614
615 MP_T *
real_to_mp(NODE_T * p,MP_T * z,double x,int digits)616 real_to_mp (NODE_T * p, MP_T * z, double x, int digits)
617 {
618 int j, k, sign_x, sum, weight;
619 int expo;
620 double a;
621 MP_T *u;
622 SET_MP_ZERO (z, digits);
623 if (x == 0.0) {
624 return (z);
625 }
626 /* Small integers can be done better by int_to_mp */
627 if (ABS (x) < MP_RADIX && (double) (int) x == x) {
628 return (int_to_mp (p, z, (int) x, digits));
629 }
630 sign_x = SIGN (x);
631 /* Scale to [0, 0.1> */
632 a = x = ABS (x);
633 expo = (int) log10 (a);
634 a /= ten_up (expo);
635 expo--;
636 if (a >= 1) {
637 a /= 10;
638 expo++;
639 }
640 /* Transport digits of x to the mantissa of z */
641 k = 0;
642 j = 1;
643 sum = 0;
644 weight = (MP_RADIX / 10);
645 u = &MP_DIGIT (z, 1);
646 while (j <= digits && k < DBL_DIG) {
647 double y = floor (a * 10);
648 int value = (int) y;
649 a = a * 10 - y;
650 sum += weight * value;
651 weight /= 10;
652 if (weight < 1) {
653 (u++)[0] = (MP_T) sum;
654 sum = 0;
655 weight = (MP_RADIX / 10);
656 }
657 k++;
658 }
659 /* Store the last digits */
660 if (j <= digits) {
661 u[0] = (MP_T) sum;
662 }
663 (void) align_mp (z, &expo, digits);
664 MP_EXPONENT (z) = (MP_T) expo;
665 MP_DIGIT (z, 1) *= sign_x;
666 CHECK_MP_EXPONENT (p, z);
667 return (z);
668 }
669
670 /**
671 @brief Convert multi-precision number to double.
672 @param p Node in syntax tree.
673 @param z Multiprecision number.
674 @param digits Precision in mp-digits.
675 @return Result "z".
676 **/
677
678 double
mp_to_real(NODE_T * p,MP_T * z,int digits)679 mp_to_real (NODE_T * p, MP_T * z, int digits)
680 {
681 /* This routine looks a lot like "strtod" */
682 (void) p;
683 if (MP_EXPONENT (z) * (MP_T) LOG_MP_BASE <= (MP_T) DBL_MIN_10_EXP) {
684 return (0);
685 } else {
686 int j;
687 double sum = 0, weight;
688 weight = ten_up ((int) (MP_EXPONENT (z) * LOG_MP_BASE));
689 for (j = 1; j <= digits && (j - 2) * LOG_MP_BASE <= DBL_DIG; j++) {
690 sum += ABS (MP_DIGIT (z, j)) * weight;
691 weight /= MP_RADIX;
692 }
693 CHECK_REAL_REPRESENTATION (p, sum);
694 return (MP_DIGIT (z, 1) >= 0 ? sum : -sum);
695 }
696 }
697
698 /**
699 @brief Convert z to a row of unsigned in the stack.
700 @param p Node in syntax tree.
701 @param z Multiprecision number.
702 @param m Mode of "z".
703 @return Result "z".
704 **/
705
706 unsigned *
stack_mp_bits(NODE_T * p,MP_T * z,MOID_T * m)707 stack_mp_bits (NODE_T * p, MP_T * z, MOID_T * m)
708 {
709 int digits = DIGITS (m), words = get_mp_bits_words (m), k, lim;
710 unsigned *row, mask;
711 MP_T *u, *v, *w;
712 row = (unsigned *) STACK_ADDRESS (stack_pointer);
713 INCREMENT_STACK_POINTER (p, words * SIZE_AL (unsigned));
714 STACK_MP (u, p, digits);
715 STACK_MP (v, p, digits);
716 STACK_MP (w, p, digits);
717 MOVE_MP (u, z, digits);
718 /* Argument check */
719 if (MP_DIGIT (u, 1) < 0.0) {
720 errno = EDOM;
721 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, m);
722 exit_genie (p, A68_RUNTIME_ERROR);
723 }
724 /* Convert radix MP_BITS_RADIX number */
725 for (k = words - 1; k >= 0; k--) {
726 MOVE_MP (w, u, digits);
727 (void) over_mp_digit (p, u, u, (MP_T) MP_BITS_RADIX, digits);
728 (void) mul_mp_digit (p, v, u, (MP_T) MP_BITS_RADIX, digits);
729 (void) sub_mp (p, v, w, v, digits);
730 row[k] = (unsigned) MP_DIGIT (v, 1);
731 }
732 /* Test on overflow: too many bits or not reduced to 0 */
733 mask = 0x1;
734 lim = get_mp_bits_width (m) % MP_BITS_BITS;
735 for (k = 1; k < lim; k++) {
736 mask <<= 1;
737 mask |= 0x1;
738 }
739 if ((row[0] & ~mask) != 0x0 || MP_DIGIT (u, 1) != 0.0) {
740 errno = ERANGE;
741 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, m);
742 exit_genie (p, A68_RUNTIME_ERROR);
743 }
744 /* Exit */
745 return (row);
746 }
747
748 /**
749 @brief Whether LONG BITS value is in range.
750 @param p Node in syntax tree.
751 @param u Multiprecision number.
752 @param m Mode of "u".
753 **/
754
755 void
check_long_bits_value(NODE_T * p,MP_T * u,MOID_T * m)756 check_long_bits_value (NODE_T * p, MP_T * u, MOID_T * m)
757 {
758 if (MP_EXPONENT (u) >= (MP_T) (DIGITS (m) - 1)) {
759 ADDR_T pop_sp = stack_pointer;
760 (void) stack_mp_bits (p, u, m);
761 stack_pointer = pop_sp;
762 }
763 }
764
765 /**
766 @brief Convert row of unsigned to LONG BITS.
767 @param p Node in syntax tree.
768 @param u Multiprecision number.
769 @param row
770 @param m Mode of "u".
771 @return Result "u".
772 **/
773
774 MP_T *
pack_mp_bits(NODE_T * p,MP_T * u,unsigned * row,MOID_T * m)775 pack_mp_bits (NODE_T * p, MP_T * u, unsigned *row, MOID_T * m)
776 {
777 int digits = DIGITS (m), words = get_mp_bits_words (m), k, lim;
778 ADDR_T pop_sp = stack_pointer;
779 MP_T *v, *w;
780 /* Discard excess bits */
781 unsigned mask = 0x1, musk = 0x0;
782 STACK_MP (v, p, digits);
783 STACK_MP (w, p, digits);
784 lim = get_mp_bits_width (m) % MP_BITS_BITS;
785 for (k = 1; k < lim; k++) {
786 mask <<= 1;
787 mask |= 0x1;
788 }
789 row[0] &= mask;
790 for (k = 1; k < (BITS_WIDTH - MP_BITS_BITS); k++) {
791 musk <<= 1;
792 }
793 for (k = 0; k < MP_BITS_BITS; k++) {
794 musk <<= 1;
795 musk |= 0x1;
796 }
797 /* Convert */
798 SET_MP_ZERO (u, digits);
799 (void) set_mp_short (v, (MP_T) 1, 0, digits);
800 for (k = words - 1; k >= 0; k--) {
801 (void) mul_mp_digit (p, w, v, (MP_T) (musk & row[k]), digits);
802 (void) add_mp (p, u, u, w, digits);
803 if (k != 0) {
804 (void) mul_mp_digit (p, v, v, (MP_T) MP_BITS_RADIX, digits);
805 }
806 }
807 MP_STATUS (u) = (MP_T) INIT_MASK;
808 stack_pointer = pop_sp;
809 return (u);
810 }
811
812 /**
813 @brief Normalise positive intermediate, fast.
814 @param w Argument.
815 @param k Last digit to normalise.
816 @param digits Precision in mp-digits.
817 **/
818
819 static void
norm_mp_light(MP_T * w,int k,int digits)820 norm_mp_light (MP_T * w, int k, int digits)
821 {
822 /* Bring every digit back to [0 .. MP_RADIX> */
823 int j;
824 MP_T *z;
825 for (j = digits, z = &MP_DIGIT (w, digits); j >= k; j--, z--) {
826 if (z[0] >= MP_RADIX) {
827 z[0] -= (MP_T) MP_RADIX;
828 z[-1] += 1;
829 } else if (z[0] < 0) {
830 z[0] += (MP_T) MP_RADIX;
831 z[-1] -= 1;
832 }
833 }
834 }
835
836 /**
837 @brief Normalise positive intermediate.
838 @param w Argument.
839 @param k Last digit to normalise.
840 @param digits Precision in mp-digits.
841 **/
842
843 static void
norm_mp(MP_T * w,int k,int digits)844 norm_mp (MP_T * w, int k, int digits)
845 {
846 /* Bring every digit back to [0 .. MP_RADIX> */
847 int j;
848 MP_T *z;
849 for (j = digits, z = &MP_DIGIT (w, digits); j >= k; j--, z--) {
850 if (z[0] >= (MP_T) MP_RADIX) {
851 MP_T carry = (MP_T) ((int) (z[0] / (MP_T) MP_RADIX));
852 z[0] -= carry * (MP_T) MP_RADIX;
853 z[-1] += carry;
854 } else if (z[0] < (MP_T) 0) {
855 MP_T carry = (MP_T) 1 + (MP_T) ((int) ((-z[0] - 1) / (MP_T) MP_RADIX));
856 z[0] += carry * (MP_T) MP_RADIX;
857 z[-1] -= carry;
858 }
859 }
860 }
861
862 /**
863 @brief Round multi-precision number.
864 @param z Result.
865 @param w Argument, must be positive.
866 @param digits Precision in mp-digits.
867 **/
868
869 static void
round_internal_mp(MP_T * z,MP_T * w,int digits)870 round_internal_mp (MP_T * z, MP_T * w, int digits)
871 {
872 /* Assume that w has precision of at least 2 + digits */
873 int last = (MP_DIGIT (w, 1) == 0 ? 2 + digits : 1 + digits);
874 if (MP_DIGIT (w, last) >= MP_RADIX / 2) {
875 MP_DIGIT (w, last - 1) += 1;
876 }
877 if (MP_DIGIT (w, last - 1) >= MP_RADIX) {
878 norm_mp (w, 2, last);
879 }
880 if (MP_DIGIT (w, 1) == 0) {
881 MOVE_DIGITS (&MP_DIGIT (z, 1), &MP_DIGIT (w, 2), digits);
882 MP_EXPONENT (z) = MP_EXPONENT (w) - 1;
883 } else {
884 /* Normally z != w, so no test on this */
885 MOVE_DIGITS (&MP_EXPONENT (z), &MP_EXPONENT (w), (1 + digits));
886 }
887 /* Zero is zero is zero */
888 if (MP_DIGIT (z, 1) == 0) {
889 MP_EXPONENT (z) = (MP_T) 0;
890 }
891 }
892
893 /**
894 @brief Truncate at decimal point.
895 @param p Node in syntax tree.
896 @param z Result.
897 @param x Argument.
898 @param digits Precision in mp-digits.
899 **/
900
901 void
trunc_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)902 trunc_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
903 {
904 if (MP_EXPONENT (x) < 0) {
905 SET_MP_ZERO (z, digits);
906 } else if (MP_EXPONENT (x) >= (MP_T) digits) {
907 errno = EDOM;
908 diagnostic_node (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, (IS (MOID (p), PROC_SYMBOL) ? SUB_MOID (p) : MOID (p)));
909 exit_genie (p, A68_RUNTIME_ERROR);
910 } else {
911 int k;
912 MOVE_MP (z, x, digits);
913 for (k = (int) (MP_EXPONENT (x) + 2); k <= digits; k++) {
914 MP_DIGIT (z, k) = (MP_T) 0;
915 }
916 }
917 }
918
919 /**
920 @brief Shorten and round.
921 @param p Node in syntax tree.
922 @param z Result.
923 @param digits Precision in mp-digits.
924 @param x Multiprecision number.
925 @param digits_x Precision of "x".
926 @return Result "z".
927 **/
928
929 MP_T *
shorten_mp(NODE_T * p,MP_T * z,int digits,MP_T * x,int digits_x)930 shorten_mp (NODE_T * p, MP_T * z, int digits, MP_T * x, int digits_x)
931 {
932 if (digits >= digits_x) {
933 errno = EDOM;
934 return (NO_MP);
935 } else {
936 /* Reserve extra digits for proper rounding */
937 int pop_sp = stack_pointer, digits_h = digits + 2;
938 MP_T *w;
939 BOOL_T negative = (BOOL_T) (MP_DIGIT (x, 1) < 0);
940 STACK_MP (w, p, digits_h);
941 if (negative) {
942 MP_DIGIT (x, 1) = -MP_DIGIT (x, 1);
943 }
944 MP_STATUS (w) = (MP_T) 0;
945 MP_EXPONENT (w) = MP_EXPONENT (x) + 1;
946 MP_DIGIT (w, 1) = (MP_T) 0;
947 MOVE_DIGITS (&MP_DIGIT (w, 2), &MP_DIGIT (x, 1), digits + 1);
948 round_internal_mp (z, w, digits);
949 if (negative) {
950 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
951 }
952 stack_pointer = pop_sp;
953 return (z);
954 }
955 }
956
957 /**
958 @brief Lengthen x and assign to z.
959 @param p Node in syntax tree.
960 @param z Multiprecision number.
961 @param digits_z Precision in mp-digits of "z".
962 @param x Multiprecision number.
963 @param digits_x Precision in mp-digits of "x".
964 @return Result "z".
965 **/
966
967 MP_T *
lengthen_mp(NODE_T * p,MP_T * z,int digits_z,MP_T * x,int digits_x)968 lengthen_mp (NODE_T * p, MP_T * z, int digits_z, MP_T * x, int digits_x)
969 {
970 int j;
971 (void) p;
972 if ((unsigned) digits_z > (unsigned) digits_x) {
973 if (z != x) {
974 MOVE_DIGITS (&MP_DIGIT (z, 1), &MP_DIGIT (x, 1), digits_x);
975 MP_EXPONENT (z) = MP_EXPONENT (x);
976 MP_STATUS (z) = MP_STATUS (x);
977 }
978 for (j = 1 + digits_x; j <= digits_z; j++) {
979 MP_DIGIT (z, j) = (MP_T) 0;
980 }
981 }
982 return (z);
983 }
984
985 /**
986 @brief Set "z" to the sum of positive "x" and positive "y".
987 @param p Node in syntax tree.
988 @param z Multiprecision number.
989 @param x Multiprecision number.
990 @param y Multiprecision number.
991 @param digits Precision in mp-digits.
992 @return Result "z".
993 **/
994
995 MP_T *
add_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)996 add_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
997 {
998 ADDR_T pop_sp = stack_pointer;
999 MP_T *w, z_1, x_1 = MP_DIGIT (x, 1), y_1 = MP_DIGIT (y, 1);
1000 MP_STATUS (z) = (MP_T) INIT_MASK;
1001 /* Trivial cases */
1002 if (MP_DIGIT (x, 1) == (MP_T) 0) {
1003 MOVE_MP (z, y, digits);
1004 return (z);
1005 } else if (MP_DIGIT (y, 1) == 0) {
1006 MOVE_MP (z, x, digits);
1007 return (z);
1008 }
1009 /* We want positive arguments */
1010 MP_DIGIT (x, 1) = ABS (x_1);
1011 MP_DIGIT (y, 1) = ABS (y_1);
1012 if (x_1 >= 0 && y_1 < 0) {
1013 (void) sub_mp (p, z, x, y, digits);
1014 } else if (x_1 < 0 && y_1 >= 0) {
1015 (void) sub_mp (p, z, y, x, digits);
1016 } else if (x_1 < 0 && y_1 < 0) {
1017 (void) add_mp (p, z, x, y, digits);
1018 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
1019 } else {
1020 /* Add */
1021 int j, digits_h = 2 + digits;
1022 STACK_MP (w, p, digits_h);
1023 MP_DIGIT (w, 1) = (MP_T) 0;
1024 if (MP_EXPONENT (x) == MP_EXPONENT (y)) {
1025 MP_EXPONENT (w) = (MP_T) 1 + MP_EXPONENT (x);
1026 for (j = 1; j <= digits; j++) {
1027 MP_DIGIT (w, j + 1) = MP_DIGIT (x, j) + MP_DIGIT (y, j);
1028 }
1029 MP_DIGIT (w, digits_h) = (MP_T) 0;
1030 } else if (MP_EXPONENT (x) > MP_EXPONENT (y)) {
1031 int shl_y = (int) MP_EXPONENT (x) - (int) MP_EXPONENT (y);
1032 MP_EXPONENT (w) = (MP_T) 1 + MP_EXPONENT (x);
1033 for (j = 1; j < digits_h; j++) {
1034 int i_y = j - (int) shl_y;
1035 MP_T x_j = (j > digits ? 0 : MP_DIGIT (x, j));
1036 MP_T y_j = (i_y <= 0 || i_y > digits ? 0 : MP_DIGIT (y, i_y));
1037 MP_DIGIT (w, j + 1) = x_j + y_j;
1038 }
1039 } else {
1040 int shl_x = (int) MP_EXPONENT (y) - (int) MP_EXPONENT (x);
1041 MP_EXPONENT (w) = (MP_T) 1 + MP_EXPONENT (y);
1042 for (j = 1; j < digits_h; j++) {
1043 int i_x = j - (int) shl_x;
1044 MP_T x_j = (i_x <= 0 || i_x > digits ? 0 : MP_DIGIT (x, i_x));
1045 MP_T y_j = (j > digits ? 0 : MP_DIGIT (y, j));
1046 MP_DIGIT (w, j + 1) = x_j + y_j;
1047 }
1048 }
1049 norm_mp_light (w, 2, digits_h);
1050 round_internal_mp (z, w, digits);
1051 CHECK_MP_EXPONENT (p, z);
1052 }
1053 /* Restore and exit */
1054 stack_pointer = pop_sp;
1055 z_1 = MP_DIGIT (z, 1);
1056 MP_DIGIT (x, 1) = x_1;
1057 MP_DIGIT (y, 1) = y_1;
1058 MP_DIGIT (z, 1) = z_1; /* In case z IS x OR z IS y */
1059 return (z);
1060 }
1061
1062 /**
1063 @brief Set "z" to the difference of positive "x" and positive "y".
1064 @param p Node in syntax tree.
1065 @param z Multiprecision number.
1066 @param x Multiprecision number.
1067 @param y Multiprecision number.
1068 @param digits Precision in mp-digits.
1069 @return Result "z".
1070 **/
1071
1072 MP_T *
sub_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)1073 sub_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
1074 {
1075 ADDR_T pop_sp = stack_pointer;
1076 int fnz, k;
1077 MP_T *w, z_1, x_1 = MP_DIGIT (x, 1), y_1 = MP_DIGIT (y, 1);
1078 BOOL_T negative = A68_FALSE;
1079 MP_STATUS (z) = (MP_T) INIT_MASK;
1080 /* Trivial cases */
1081 if (MP_DIGIT (x, 1) == (MP_T) 0) {
1082 MOVE_MP (z, y, digits);
1083 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
1084 return (z);
1085 } else if (MP_DIGIT (y, 1) == (MP_T) 0) {
1086 MOVE_MP (z, x, digits);
1087 return (z);
1088 }
1089 MP_DIGIT (x, 1) = ABS (x_1);
1090 MP_DIGIT (y, 1) = ABS (y_1);
1091 /* We want positive arguments */
1092 if (x_1 >= 0 && y_1 < 0) {
1093 (void) add_mp (p, z, x, y, digits);
1094 } else if (x_1 < 0 && y_1 >= 0) {
1095 (void) add_mp (p, z, y, x, digits);
1096 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
1097 } else if (x_1 < 0 && y_1 < 0) {
1098 (void) sub_mp (p, z, y, x, digits);
1099 } else {
1100 /* Subtract */
1101 int j, digits_h = 2 + digits;
1102 STACK_MP (w, p, digits_h);
1103 MP_DIGIT (w, 1) = (MP_T) 0;
1104 if (MP_EXPONENT (x) == MP_EXPONENT (y)) {
1105 MP_EXPONENT (w) = (MP_T) 1 + MP_EXPONENT (x);
1106 for (j = 1; j <= digits; j++) {
1107 MP_DIGIT (w, j + 1) = MP_DIGIT (x, j) - MP_DIGIT (y, j);
1108 }
1109 MP_DIGIT (w, digits_h) = (MP_T) 0;
1110 } else if (MP_EXPONENT (x) > MP_EXPONENT (y)) {
1111 int shl_y = (int) MP_EXPONENT (x) - (int) MP_EXPONENT (y);
1112 MP_EXPONENT (w) = (MP_T) 1 + MP_EXPONENT (x);
1113 for (j = 1; j < digits_h; j++) {
1114 int i_y = j - (int) shl_y;
1115 MP_T x_j = (j > digits ? 0 : MP_DIGIT (x, j));
1116 MP_T y_j = (i_y <= 0 || i_y > digits ? 0 : MP_DIGIT (y, i_y));
1117 MP_DIGIT (w, j + 1) = x_j - y_j;
1118 }
1119 } else {
1120 int shl_x = (int) MP_EXPONENT (y) - (int) MP_EXPONENT (x);
1121 MP_EXPONENT (w) = (MP_T) 1 + MP_EXPONENT (y);
1122 for (j = 1; j < digits_h; j++) {
1123 int i_x = j - (int) shl_x;
1124 MP_T x_j = (i_x <= 0 || i_x > digits ? 0 : MP_DIGIT (x, i_x));
1125 MP_T y_j = (j > digits ? 0 : MP_DIGIT (y, j));
1126 MP_DIGIT (w, j + 1) = x_j - y_j;
1127 }
1128 }
1129 /* Correct if we subtract large from small */
1130 if (MP_DIGIT (w, 2) <= 0) {
1131 fnz = -1;
1132 for (j = 2; j <= digits_h && fnz < 0; j++) {
1133 if (MP_DIGIT (w, j) != 0) {
1134 fnz = j;
1135 }
1136 }
1137 negative = (BOOL_T) (MP_DIGIT (w, fnz) < 0);
1138 if (negative) {
1139 for (j = fnz; j <= digits_h; j++) {
1140 MP_DIGIT (w, j) = -MP_DIGIT (w, j);
1141 }
1142 }
1143 }
1144 /* Normalise */
1145 norm_mp_light (w, 2, digits_h);
1146 fnz = -1;
1147 for (j = 1; j <= digits_h && fnz < 0; j++) {
1148 if (MP_DIGIT (w, j) != 0) {
1149 fnz = j;
1150 }
1151 }
1152 if (fnz > 1) {
1153 int j2 = fnz - 1;
1154 for (k = 1; k <= digits_h - j2; k++) {
1155 MP_DIGIT (w, k) = MP_DIGIT (w, k + j2);
1156 MP_DIGIT (w, k + j2) = (MP_T) 0;
1157 }
1158 MP_EXPONENT (w) -= j2;
1159 }
1160 /* Round */
1161 round_internal_mp (z, w, digits);
1162 if (negative) {
1163 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
1164 }
1165 CHECK_MP_EXPONENT (p, z);
1166 }
1167 /* Restore and exit */
1168 stack_pointer = pop_sp;
1169 z_1 = MP_DIGIT (z, 1);
1170 MP_DIGIT (x, 1) = x_1;
1171 MP_DIGIT (y, 1) = y_1;
1172 MP_DIGIT (z, 1) = z_1; /* In case z IS x OR z IS y */
1173 return (z);
1174 }
1175
1176 /**
1177 @brief Set "z" to the product of "x" and "y".
1178 @param p Node in syntax tree.
1179 @param z Multiprecision number.
1180 @param x Multiprecision number.
1181 @param y Multiprecision number.
1182 @param digits Precision in mp-digits.
1183 @return Result "z".
1184 **/
1185
1186 MP_T *
mul_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)1187 mul_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
1188 {
1189 MP_T *w, z_1, x_1 = MP_DIGIT (x, 1), y_1 = MP_DIGIT (y, 1);
1190 int i, oflow, digits_h = 2 + digits;
1191 ADDR_T pop_sp = stack_pointer;
1192 MP_DIGIT (x, 1) = ABS (x_1);
1193 MP_DIGIT (y, 1) = ABS (y_1);
1194 MP_STATUS (z) = (MP_T) INIT_MASK;
1195 if (x_1 == 0 || y_1 == 0) {
1196 stack_pointer = pop_sp;
1197 MP_DIGIT (x, 1) = x_1;
1198 MP_DIGIT (y, 1) = y_1;
1199 SET_MP_ZERO (z, digits);
1200 return (z);
1201 }
1202 /* Calculate z = x * y */
1203 STACK_MP (w, p, digits_h);
1204 SET_MP_ZERO (w, digits_h);
1205 MP_EXPONENT (w) = MP_EXPONENT (x) + MP_EXPONENT (y) + 1;
1206 oflow = (int) (floor) ((double) MAX_REPR_INT / (2 * (double) MP_RADIX * (double) MP_RADIX)) - 1;
1207 ABEND (oflow <= 1, "inadequate MP_RADIX", NO_TEXT);
1208 if (digits < oflow) {
1209 for (i = digits; i >= 1; i--) {
1210 MP_T yi = MP_DIGIT (y, i);
1211 if (yi != 0) {
1212 int k = digits_h - i;
1213 int j = (k > digits ? digits : k);
1214 MP_T *u = &MP_DIGIT (w, i + j);
1215 MP_T *v = &MP_DIGIT (x, j);
1216 while (j-- >= 1) {
1217 (u--)[0] += yi * (v--)[0];
1218 }
1219 }
1220 }
1221 } else {
1222 for (i = digits; i >= 1; i--) {
1223 MP_T yi = MP_DIGIT (y, i);
1224 if (yi != 0) {
1225 int k = digits_h - i;
1226 int j = (k > digits ? digits : k);
1227 MP_T *u = &MP_DIGIT (w, i + j);
1228 MP_T *v = &MP_DIGIT (x, j);
1229 if ((digits - i + 1) % oflow == 0) {
1230 norm_mp (w, 2, digits_h);
1231 }
1232 while (j-- >= 1) {
1233 (u--)[0] += yi * (v--)[0];
1234 }
1235 }
1236 }
1237 }
1238 norm_mp (w, 2, digits_h);
1239 round_internal_mp (z, w, digits);
1240 /* Restore and exit */
1241 stack_pointer = pop_sp;
1242 z_1 = MP_DIGIT (z, 1);
1243 MP_DIGIT (x, 1) = x_1;
1244 MP_DIGIT (y, 1) = y_1;
1245 MP_DIGIT (z, 1) = ((x_1 * y_1) >= 0 ? z_1 : -z_1);
1246 CHECK_MP_EXPONENT (p, z);
1247 return (z);
1248 }
1249
1250 /**
1251 @brief Set "z" to the quotient of "x" and "y".
1252 @param p Node in syntax tree.
1253 @param z Multiprecision number.
1254 @param x Multiprecision number.
1255 @param y Multiprecision number.
1256 @param digits Precision in mp-digits.
1257 @return Result "z".
1258 **/
1259
1260 MP_T *
div_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)1261 div_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
1262 {
1263 /*
1264 This routine is an implementation of
1265
1266 D. M. Smith, "A Multiple-Precision Division Algorithm"
1267 Mathematics of Computation 66 (1996) 157-163.
1268
1269 This algorithm is O(N ** 2) but runs faster than straightforward methods by
1270 skipping most of the intermediate normalisation and recovering from wrong
1271 guesses without separate correction steps.
1272 */
1273 double xd;
1274 MP_T *t, *w, z_1, x_1 = MP_DIGIT (x, 1), y_1 = MP_DIGIT (y, 1);
1275 int k, oflow, digits_w = 4 + digits;
1276 ADDR_T pop_sp = stack_pointer;
1277 if (y_1 == 0) {
1278 errno = ERANGE;
1279 return (NO_MP);
1280 }
1281 /* Determine normalisation interval assuming that q < 2b in each step */
1282 oflow = (int) (floor) ((double) MAX_REPR_INT / (3 * (double) MP_RADIX * (double) MP_RADIX)) - 1;
1283 ABEND (oflow <= 1, "inadequate MP_RADIX", NO_TEXT);
1284 MP_DIGIT (x, 1) = ABS (x_1);
1285 MP_DIGIT (y, 1) = ABS (y_1);
1286 MP_STATUS (z) = (MP_T) INIT_MASK;
1287 /* `w' will be the working nominator in which the quotient develops */
1288 STACK_MP (w, p, digits_w);
1289 MP_EXPONENT (w) = MP_EXPONENT (x) - MP_EXPONENT (y);
1290 MP_DIGIT (w, 1) = (MP_T) 0;
1291 MOVE_DIGITS (&MP_DIGIT (w, 2), &MP_DIGIT (x, 1), digits);
1292 MP_DIGIT (w, digits + 2) = (MP_T) 0;
1293 MP_DIGIT (w, digits + 3) = (MP_T) 0;
1294 MP_DIGIT (w, digits + 4) = (MP_T) 0;
1295 /* Estimate the denominator. Take four terms to also suit small MP_RADIX */
1296 xd = (MP_DIGIT (y, 1) * MP_RADIX + MP_DIGIT (y, 2)) * MP_RADIX + MP_DIGIT (y, 3) + MP_DIGIT (y, 4) / MP_RADIX;
1297 t = &MP_DIGIT (w, 2);
1298 if (digits + 2 < oflow) {
1299 for (k = 1; k <= digits + 2; k++, t++) {
1300 double xn, q;
1301 int first = k + 2;
1302 /* Estimate quotient digit */
1303 xn = ((t[-1] * MP_RADIX + t[0]) * MP_RADIX + t[1]) * MP_RADIX + (digits_w >= (first + 2) ? t[2] : 0);
1304 q = (double) ((int) (xn / xd));
1305 if (q != 0) {
1306 /* Correct the nominator */
1307 int j, len = k + digits + 1;
1308 int lim = (len < digits_w ? len : digits_w);
1309 MP_T *u = t, *v = &MP_DIGIT (y, 1);
1310 for (j = first; j <= lim; j++) {
1311 (u++)[0] -= q * (v++)[0];
1312 }
1313 }
1314 t[0] += (t[-1] * MP_RADIX);
1315 t[-1] = q;
1316 }
1317 } else {
1318 for (k = 1; k <= digits + 2; k++, t++) {
1319 double xn, q;
1320 int first = k + 2;
1321 if (k % oflow == 0) {
1322 norm_mp (w, first, digits_w);
1323 }
1324 /* Estimate quotient digit */
1325 xn = ((t[-1] * MP_RADIX + t[0]) * MP_RADIX + t[1]) * MP_RADIX + (digits_w >= (first + 2) ? t[2] : 0);
1326 q = (double) ((int) (xn / xd));
1327 if (q != 0) {
1328 /* Correct the nominator */
1329 int j, len = k + digits + 1;
1330 int lim = (len < digits_w ? len : digits_w);
1331 MP_T *u = t, *v = &MP_DIGIT (y, 1);
1332 for (j = first; j <= lim; j++) {
1333 (u++)[0] -= q * (v++)[0];
1334 }
1335 }
1336 t[0] += (t[-1] * MP_RADIX);
1337 t[-1] = q;
1338 }
1339 }
1340 norm_mp (w, 2, digits_w);
1341 round_internal_mp (z, w, digits);
1342 /* Restore and exit */
1343 stack_pointer = pop_sp;
1344 z_1 = MP_DIGIT (z, 1);
1345 MP_DIGIT (x, 1) = x_1;
1346 MP_DIGIT (y, 1) = y_1;
1347 MP_DIGIT (z, 1) = ((x_1 * y_1) >= 0 ? z_1 : -z_1);
1348 CHECK_MP_EXPONENT (p, z);
1349 return (z);
1350 }
1351
1352 /**
1353 @brief Set "z" to the integer quotient of "x" and "y".
1354 @param p Node in syntax tree.
1355 @param z Multiprecision number.
1356 @param x Multiprecision number.
1357 @param y Multiprecision number.
1358 @param digits Precision in mp-digits.
1359 @return Result "z".
1360 **/
1361
1362 MP_T *
over_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)1363 over_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
1364 {
1365 int digits_g = FUN_DIGITS (digits);
1366 MP_T *x_g, *y_g, *z_g;
1367 ADDR_T pop_sp = stack_pointer;
1368 if (MP_DIGIT (y, 1) == 0) {
1369 errno = ERANGE;
1370 return (NO_MP);
1371 }
1372 STACK_MP (x_g, p, digits_g);
1373 STACK_MP (y_g, p, digits_g);
1374 STACK_MP (z_g, p, digits_g);
1375 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1376 (void) lengthen_mp (p, y_g, digits_g, y, digits);
1377 (void) div_mp (p, z_g, x_g, y_g, digits_g);
1378 trunc_mp (p, z_g, z_g, digits_g);
1379 (void) shorten_mp (p, z, digits, z_g, digits_g);
1380 MP_STATUS (z) = (MP_T) INIT_MASK;
1381 /* Restore and exit */
1382 stack_pointer = pop_sp;
1383 return (z);
1384 }
1385
1386 /**
1387 @brief Set "z" to x mod y.
1388 @param p Node in syntax tree.
1389 @param z Multiprecision number.
1390 @param x Multiprecision number.
1391 @param y Multiprecision number.
1392 @param digits Precision in mp-digits.
1393 @return Result "z".
1394 **/
1395
1396 MP_T *
mod_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)1397 mod_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
1398 {
1399 int digits_g = FUN_DIGITS (digits);
1400 ADDR_T pop_sp = stack_pointer;
1401 MP_T *x_g, *y_g, *z_g;
1402 if (MP_DIGIT (y, 1) == 0) {
1403 errno = EDOM;
1404 return (NO_MP);
1405 }
1406 STACK_MP (x_g, p, digits_g);
1407 STACK_MP (y_g, p, digits_g);
1408 STACK_MP (z_g, p, digits_g);
1409 (void) lengthen_mp (p, y_g, digits_g, y, digits);
1410 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1411 /* x mod y = x - y * trunc (x / y) */
1412 (void) over_mp (p, z_g, x_g, y_g, digits_g);
1413 (void) mul_mp (p, z_g, y_g, z_g, digits_g);
1414 (void) sub_mp (p, z_g, x_g, z_g, digits_g);
1415 (void) shorten_mp (p, z, digits, z_g, digits_g);
1416 /* Restore and exit */
1417 stack_pointer = pop_sp;
1418 return (z);
1419 }
1420
1421 /**
1422 @brief Set "z" to the product of x and digit y.
1423 @param p Node in syntax tree.
1424 @param z Multiprecision number.
1425 @param x Multiprecision number.
1426 @param y Multiprecision number.
1427 @param digits Precision in mp-digits.
1428 @return Result "z".
1429 **/
1430
1431 MP_T *
mul_mp_digit(NODE_T * p,MP_T * z,MP_T * x,MP_T y,int digits)1432 mul_mp_digit (NODE_T * p, MP_T * z, MP_T * x, MP_T y, int digits)
1433 {
1434 /* This is an O(N) routine for multiplication by a short value */
1435 MP_T *w, z_1, x_1 = MP_DIGIT (x, 1), y_1 = y, *u, *v;
1436 int j, digits_h = 2 + digits;
1437 ADDR_T pop_sp = stack_pointer;
1438 MP_DIGIT (x, 1) = ABS (x_1);
1439 MP_STATUS (z) = (MP_T) INIT_MASK;
1440 y = ABS (y_1);
1441 STACK_MP (w, p, digits_h);
1442 SET_MP_ZERO (w, digits_h);
1443 MP_EXPONENT (w) = MP_EXPONENT (x) + 1;
1444 j = digits;
1445 u = &MP_DIGIT (w, 1 + digits);
1446 v = &MP_DIGIT (x, digits);
1447 while (j-- >= 1) {
1448 (u--)[0] += y * (v--)[0];
1449 }
1450 norm_mp (w, 2, digits_h);
1451 round_internal_mp (z, w, digits);
1452 /* Restore and exit */
1453 stack_pointer = pop_sp;
1454 z_1 = MP_DIGIT (z, 1);
1455 MP_DIGIT (x, 1) = x_1;
1456 MP_DIGIT (z, 1) = ((x_1 * y_1) >= 0 ? z_1 : -z_1);
1457 CHECK_MP_EXPONENT (p, z);
1458 return (z);
1459 }
1460
1461 /**
1462 @brief Set "z" to x/2.
1463 @param p Node in syntax tree.
1464 @param z Multiprecision number.
1465 @param x Multiprecision number.
1466 @param digits Precision in mp-digits.
1467 @return Result "z".
1468 **/
1469
1470 MP_T *
half_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)1471 half_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
1472 {
1473 MP_T *w, z_1, x_1 = MP_DIGIT (x, 1), *u, *v;
1474 int j, digits_h = 2 + digits;
1475 ADDR_T pop_sp = stack_pointer;
1476 MP_DIGIT (x, 1) = ABS (x_1);
1477 MP_STATUS (z) = (MP_T) INIT_MASK;
1478 STACK_MP (w, p, digits_h);
1479 SET_MP_ZERO (w, digits_h);
1480 /* Calculate x * 0.5 */
1481 MP_EXPONENT (w) = MP_EXPONENT (x);
1482 j = digits;
1483 u = &MP_DIGIT (w, 1 + digits);
1484 v = &MP_DIGIT (x, digits);
1485 while (j-- >= 1) {
1486 (u--)[0] += (MP_RADIX / 2) * (v--)[0];
1487 }
1488 norm_mp (w, 2, digits_h);
1489 round_internal_mp (z, w, digits);
1490 /* Restore and exit */
1491 stack_pointer = pop_sp;
1492 z_1 = MP_DIGIT (z, 1);
1493 MP_DIGIT (x, 1) = x_1;
1494 MP_DIGIT (z, 1) = (x_1 >= 0 ? z_1 : -z_1);
1495 CHECK_MP_EXPONENT (p, z);
1496 return (z);
1497 }
1498
1499 /**
1500 @brief Set "z" to the quotient of x and digit y.
1501 @param p Node in syntax tree.
1502 @param z Multiprecision number.
1503 @param x Multiprecision number.
1504 @param y Multiprecision number.
1505 @param digits Precision in mp-digits.
1506 @return Result "z".
1507 **/
1508
1509 MP_T *
div_mp_digit(NODE_T * p,MP_T * z,MP_T * x,MP_T y,int digits)1510 div_mp_digit (NODE_T * p, MP_T * z, MP_T * x, MP_T y, int digits)
1511 {
1512 double xd;
1513 MP_T *t, *w, z_1, x_1 = MP_DIGIT (x, 1), y_1 = y;
1514 int k, oflow, digits_w = 4 + digits;
1515 ADDR_T pop_sp = stack_pointer;
1516 if (y == 0) {
1517 errno = ERANGE;
1518 return (NO_MP);
1519 }
1520 /* Determine normalisation interval assuming that q < 2b in each step */
1521 oflow = (int) (floor) ((double) MAX_REPR_INT / (3 * (double) MP_RADIX * (double) MP_RADIX)) - 1;
1522 ABEND (oflow <= 1, "inadequate MP_RADIX", NO_TEXT);
1523 /* Work with positive operands */
1524 MP_DIGIT (x, 1) = ABS (x_1);
1525 MP_STATUS (z) = (MP_T) INIT_MASK;
1526 y = ABS (y_1);
1527 STACK_MP (w, p, digits_w);
1528 MP_EXPONENT (w) = MP_EXPONENT (x);
1529 MP_DIGIT (w, 1) = (MP_T) 0;
1530 MOVE_DIGITS (&MP_DIGIT (w, 2), &MP_DIGIT (x, 1), digits);
1531 MP_DIGIT (w, digits + 2) = (MP_T) 0;
1532 MP_DIGIT (w, digits + 3) = (MP_T) 0;
1533 MP_DIGIT (w, digits + 4) = (MP_T) 0;
1534 /* Estimate the denominator */
1535 xd = (double) y *MP_RADIX * MP_RADIX;
1536 t = &MP_DIGIT (w, 2);
1537 if (digits + 2 < oflow) {
1538 for (k = 1; k <= digits + 2; k++, t++) {
1539 double xn, q;
1540 int first = k + 2;
1541 /* Estimate quotient digit and correct */
1542 xn = ((t[-1] * MP_RADIX + t[0]) * MP_RADIX + t[1]) * MP_RADIX + (digits_w >= (first + 2) ? t[2] : 0);
1543 q = (double) ((int) (xn / xd));
1544 t[0] += (t[-1] * MP_RADIX - q * y);
1545 t[-1] = q;
1546 }
1547 } else {
1548 for (k = 1; k <= digits + 2; k++, t++) {
1549 double xn, q;
1550 int first = k + 2;
1551 if (k % oflow == 0) {
1552 norm_mp (w, first, digits_w);
1553 }
1554 /* Estimate quotient digit and correct */
1555 xn = ((t[-1] * MP_RADIX + t[0]) * MP_RADIX + t[1]) * MP_RADIX + (digits_w >= (first + 2) ? t[2] : 0);
1556 q = (double) ((int) (xn / xd));
1557 t[0] += (t[-1] * MP_RADIX - q * y);
1558 t[-1] = q;
1559 }
1560 }
1561 norm_mp (w, 2, digits_w);
1562 round_internal_mp (z, w, digits);
1563 /* Restore and exit */
1564 stack_pointer = pop_sp;
1565 z_1 = MP_DIGIT (z, 1);
1566 MP_DIGIT (x, 1) = x_1;
1567 MP_DIGIT (z, 1) = ((x_1 * y_1) >= 0 ? z_1 : -z_1);
1568 CHECK_MP_EXPONENT (p, z);
1569 return (z);
1570 }
1571
1572 /**
1573 @brief Set "z" to the integer quotient of "x" and "y".
1574 @param p Node in syntax tree.
1575 @param z Multiprecision number.
1576 @param x Multiprecision number.
1577 @param y Multiprecision number.
1578 @param digits Precision in mp-digits.
1579 @return Result "z".
1580 **/
1581
1582 MP_T *
over_mp_digit(NODE_T * p,MP_T * z,MP_T * x,MP_T y,int digits)1583 over_mp_digit (NODE_T * p, MP_T * z, MP_T * x, MP_T y, int digits)
1584 {
1585 int digits_g = FUN_DIGITS (digits);
1586 ADDR_T pop_sp = stack_pointer;
1587 MP_T *x_g, *z_g;
1588 if (y == 0) {
1589 errno = ERANGE;
1590 return (NO_MP);
1591 }
1592 STACK_MP (x_g, p, digits_g);
1593 STACK_MP (z_g, p, digits_g);
1594 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1595 (void) div_mp_digit (p, z_g, x_g, y, digits_g);
1596 trunc_mp (p, z_g, z_g, digits_g);
1597 (void) shorten_mp (p, z, digits, z_g, digits_g);
1598 /* Restore and exit */
1599 stack_pointer = pop_sp;
1600 return (z);
1601 }
1602
1603 /**
1604 @brief Set "z" to the reciprocal of "x".
1605 @param p Node in syntax tree.
1606 @param z Multiprecision number.
1607 @param x Multiprecision number.
1608 @param digits Precision in mp-digits.
1609 @return Result "z".
1610 **/
1611
1612 MP_T *
rec_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)1613 rec_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
1614 {
1615 ADDR_T pop_sp = stack_pointer;
1616 MP_T *one;
1617 if (MP_DIGIT (x, 1) == 0) {
1618 errno = ERANGE;
1619 return (NO_MP);
1620 }
1621 STACK_MP (one, p, digits);
1622 (void) set_mp_short (one, (MP_T) 1, 0, digits);
1623 (void) div_mp (p, z, one, x, digits);
1624 /* Restore and exit */
1625 stack_pointer = pop_sp;
1626 return (z);
1627 }
1628
1629 /**
1630 @brief Set "z" to "x" ** "n".
1631 @param p Node in syntax tree.
1632 @param z Multiprecision number.
1633 @param x Multiprecision number.
1634 @param n Integer power.
1635 @param digits Precision in mp-digits.
1636 @return Result "z".
1637 **/
1638
1639 MP_T *
pow_mp_int(NODE_T * p,MP_T * z,MP_T * x,int n,int digits)1640 pow_mp_int (NODE_T * p, MP_T * z, MP_T * x, int n, int digits)
1641 {
1642 int pop_sp = stack_pointer, bit, digits_g = FUN_DIGITS (digits);
1643 BOOL_T negative;
1644 MP_T *z_g, *x_g;
1645 STACK_MP (z_g, p, digits_g);
1646 STACK_MP (x_g, p, digits_g);
1647 (void) set_mp_short (z_g, (MP_T) 1, 0, digits_g);
1648 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1649 negative = (BOOL_T) (n < 0);
1650 if (negative) {
1651 n = -n;
1652 }
1653 bit = 1;
1654 while ((unsigned) bit <= (unsigned) n) {
1655 if (n & bit) {
1656 (void) mul_mp (p, z_g, z_g, x_g, digits_g);
1657 }
1658 (void) mul_mp (p, x_g, x_g, x_g, digits_g);
1659 bit *= 2;
1660 }
1661 (void) shorten_mp (p, z, digits, z_g, digits_g);
1662 stack_pointer = pop_sp;
1663 if (negative) {
1664 (void) rec_mp (p, z, z, digits);
1665 }
1666 CHECK_MP_EXPONENT (p, z);
1667 return (z);
1668 }
1669
1670 /**
1671 @brief Set "z" to 10 ** "n".
1672 @param p Node in syntax tree.
1673 @param z Multiprecision number.
1674 @param n Integer power.
1675 @param digits Precision in mp-digits.
1676 @return Result "z".
1677 **/
1678
1679 MP_T *
mp_ten_up(NODE_T * p,MP_T * z,int n,int digits)1680 mp_ten_up (NODE_T * p, MP_T * z, int n, int digits)
1681 {
1682 int pop_sp = stack_pointer, bit, digits_g = FUN_DIGITS (digits);
1683 BOOL_T negative;
1684 MP_T *z_g, *x_g;
1685 STACK_MP (z_g, p, digits_g);
1686 STACK_MP (x_g, p, digits_g);
1687 (void) set_mp_short (x_g, (MP_T) 10, 0, digits_g);
1688 (void) set_mp_short (z_g, (MP_T) 1, 0, digits_g);
1689 negative = (BOOL_T) (n < 0);
1690 if (negative) {
1691 n = -n;
1692 }
1693 bit = 1;
1694 while ((unsigned) bit <= (unsigned) n) {
1695 if (n & bit) {
1696 (void) mul_mp (p, z_g, z_g, x_g, digits_g);
1697 }
1698 (void) mul_mp (p, x_g, x_g, x_g, digits_g);
1699 bit *= 2;
1700 }
1701 (void) shorten_mp (p, z, digits, z_g, digits_g);
1702 stack_pointer = pop_sp;
1703 if (negative) {
1704 (void) rec_mp (p, z, z, digits);
1705 }
1706 CHECK_MP_EXPONENT (p, z);
1707 return (z);
1708 }
1709
1710 /**
1711 @brief Test on |"z"| > 0.001 for argument reduction in "sin" and "exp".
1712 @param z Multiprecision number.
1713 @param digits Precision in mp-digits.
1714 @return Result "z".
1715 **/
1716
1717 static BOOL_T
eps_mp(MP_T * z,int digits)1718 eps_mp (MP_T * z, int digits)
1719 {
1720 if (MP_DIGIT (z, 1) == 0) {
1721 return (A68_FALSE);
1722 } else if (MP_EXPONENT (z) > -1) {
1723 return (A68_TRUE);
1724 } else if (MP_EXPONENT (z) < -1) {
1725 return (A68_FALSE);
1726 } else {
1727 #if (MP_RADIX == DEFAULT_MP_RADIX)
1728 /* More or less optimised for LONG and default LONG LONG precisions */
1729 return ((BOOL_T) (digits <= 10 ? ABS (MP_DIGIT (z, 1)) > 100000 : ABS (MP_DIGIT (z, 1)) > 10000));
1730 #else
1731 switch (LOG_MP_BASE) {
1732 case 3:
1733 {
1734 return (ABS (MP_DIGIT (z, 1)) > 1);
1735 }
1736 case 4:
1737 {
1738 return (ABS (MP_DIGIT (z, 1)) > 10);
1739 }
1740 case 5:
1741 {
1742 return (ABS (MP_DIGIT (z, 1)) > 100);
1743 }
1744 case 6:
1745 {
1746 return (ABS (MP_DIGIT (z, 1)) > 1000);
1747 }
1748 default:
1749 {
1750 ABEND (A68_TRUE, "unexpected mp base", "");
1751 return (A68_FALSE);
1752 }
1753 }
1754 #endif
1755 }
1756 }
1757
1758 /**
1759 @brief Set "z" to sqrt ("x").
1760 @param p Node in syntax tree.
1761 @param z Multiprecision number.
1762 @param x Multiprecision number.
1763 @param digits Precision in mp-digits.
1764 @return Result "z".
1765 **/
1766
1767 MP_T *
sqrt_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)1768 sqrt_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
1769 {
1770 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits), digits_h;
1771 MP_T *tmp, *x_g, *z_g;
1772 BOOL_T reciprocal = A68_FALSE;
1773 if (MP_DIGIT (x, 1) == 0) {
1774 stack_pointer = pop_sp;
1775 SET_MP_ZERO (z, digits);
1776 return (z);
1777 }
1778 if (MP_DIGIT (x, 1) < 0) {
1779 stack_pointer = pop_sp;
1780 errno = EDOM;
1781 return (NO_MP);
1782 }
1783 STACK_MP (z_g, p, digits_g);
1784 STACK_MP (x_g, p, digits_g);
1785 STACK_MP (tmp, p, digits_g);
1786 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1787 /* Scaling for small x; sqrt (x) = 1 / sqrt (1 / x) */
1788 if ((reciprocal = (BOOL_T) (MP_EXPONENT (x_g) < 0)) == A68_TRUE) {
1789 (void) rec_mp (p, x_g, x_g, digits_g);
1790 }
1791 if (ABS (MP_EXPONENT (x_g)) >= 2) {
1792 /* For extreme arguments we want accurate results as well */
1793 int expo = (int) MP_EXPONENT (x_g);
1794 MP_EXPONENT (x_g) = (MP_T) (expo % 2);
1795 (void) sqrt_mp (p, z_g, x_g, digits_g);
1796 MP_EXPONENT (z_g) += (MP_T) (expo / 2);
1797 } else {
1798 /* Argument is in range. Estimate the root as double */
1799 int decimals;
1800 double x_d = mp_to_real (p, x_g, digits_g);
1801 (void) real_to_mp (p, z_g, sqrt (x_d), digits_g);
1802 /* Newton's method: x<n+1> = (x<n> + a / x<n>) / 2 */
1803 decimals = DOUBLE_ACCURACY;
1804 do {
1805 decimals <<= 1;
1806 digits_h = MINIMUM (1 + decimals / LOG_MP_BASE, digits_g);
1807 (void) div_mp (p, tmp, x_g, z_g, digits_h);
1808 (void) add_mp (p, tmp, z_g, tmp, digits_h);
1809 (void) half_mp (p, z_g, tmp, digits_h);
1810 } while (decimals < 2 * digits_g * LOG_MP_BASE);
1811 }
1812 if (reciprocal) {
1813 (void) rec_mp (p, z_g, z_g, digits);
1814 }
1815 (void) shorten_mp (p, z, digits, z_g, digits_g);
1816 /* Exit */
1817 stack_pointer = pop_sp;
1818 return (z);
1819 }
1820
1821 /**
1822 @brief Set "z" to curt ("x"), the cube root.
1823 @param p Node in syntax tree.
1824 @param z Multiprecision number.
1825 @param x Multiprecision number.
1826 @param digits Precision in mp-digits.
1827 @return Result "z".
1828 **/
1829
1830 MP_T *
curt_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)1831 curt_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
1832 {
1833 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits), digits_h;
1834 MP_T *tmp, *x_g, *z_g;
1835 BOOL_T reciprocal = A68_FALSE, change_sign = A68_FALSE;
1836 if (MP_DIGIT (x, 1) == 0) {
1837 stack_pointer = pop_sp;
1838 SET_MP_ZERO (z, digits);
1839 return (z);
1840 }
1841 if (MP_DIGIT (x, 1) < 0) {
1842 change_sign = A68_TRUE;
1843 MP_DIGIT (x, 1) = -MP_DIGIT (x, 1);
1844 }
1845 STACK_MP (z_g, p, digits_g);
1846 STACK_MP (x_g, p, digits_g);
1847 STACK_MP (tmp, p, digits_g);
1848 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1849 /* Scaling for small x; curt (x) = 1 / curt (1 / x) */
1850 if ((reciprocal = (BOOL_T) (MP_EXPONENT (x_g) < 0)) == A68_TRUE) {
1851 (void) rec_mp (p, x_g, x_g, digits_g);
1852 }
1853 if (ABS (MP_EXPONENT (x_g)) >= 3) {
1854 /* For extreme arguments we want accurate results as well */
1855 int expo = (int) MP_EXPONENT (x_g);
1856 MP_EXPONENT (x_g) = (MP_T) (expo % 3);
1857 (void) curt_mp (p, z_g, x_g, digits_g);
1858 MP_EXPONENT (z_g) += (MP_T) (expo / 3);
1859 } else {
1860 /* Argument is in range. Estimate the root as double */
1861 int decimals;
1862 (void) real_to_mp (p, z_g, curt (mp_to_real (p, x_g, digits_g)), digits_g);
1863 /* Newton's method: x<n+1> = (2 x<n> + a / x<n> ^ 2) / 3 */
1864 decimals = DOUBLE_ACCURACY;
1865 do {
1866 decimals <<= 1;
1867 digits_h = MINIMUM (1 + decimals / LOG_MP_BASE, digits_g);
1868 (void) mul_mp (p, tmp, z_g, z_g, digits_h);
1869 (void) div_mp (p, tmp, x_g, tmp, digits_h);
1870 (void) add_mp (p, tmp, z_g, tmp, digits_h);
1871 (void) add_mp (p, tmp, z_g, tmp, digits_h);
1872 (void) div_mp_digit (p, z_g, tmp, (MP_T) 3, digits_h);
1873 } while (decimals < digits_g * LOG_MP_BASE);
1874 }
1875 if (reciprocal) {
1876 (void) rec_mp (p, z_g, z_g, digits);
1877 }
1878 (void) shorten_mp (p, z, digits, z_g, digits_g);
1879 /* Exit */
1880 stack_pointer = pop_sp;
1881 if (change_sign) {
1882 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
1883 }
1884 return (z);
1885 }
1886
1887 /**
1888 @brief Set "z" to sqrt ("x"^2 + "y"^2).
1889 @param p Node in syntax tree.
1890 @param z Multiprecision number.
1891 @param x Multiprecision number.
1892 @param y Multiprecision number.
1893 @param digits Precision in mp-digits.
1894 @return Result "z".
1895 **/
1896
1897 MP_T *
hypot_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)1898 hypot_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
1899 {
1900 ADDR_T pop_sp = stack_pointer;
1901 MP_T *t, *u, *v;
1902 STACK_MP (t, p, digits);
1903 STACK_MP (u, p, digits);
1904 STACK_MP (v, p, digits);
1905 MOVE_MP (u, x, digits);
1906 MOVE_MP (v, y, digits);
1907 MP_DIGIT (u, 1) = ABS (MP_DIGIT (u, 1));
1908 MP_DIGIT (v, 1) = ABS (MP_DIGIT (v, 1));
1909 if (IS_ZERO_MP (u)) {
1910 MOVE_MP (z, v, digits);
1911 } else if (IS_ZERO_MP (v)) {
1912 MOVE_MP (z, u, digits);
1913 } else {
1914 (void) set_mp_short (t, (MP_T) 1, 0, digits);
1915 (void) sub_mp (p, z, u, v, digits);
1916 if (MP_DIGIT (z, 1) > 0) {
1917 (void) div_mp (p, z, v, u, digits);
1918 (void) mul_mp (p, z, z, z, digits);
1919 (void) add_mp (p, z, t, z, digits);
1920 (void) sqrt_mp (p, z, z, digits);
1921 (void) mul_mp (p, z, u, z, digits);
1922 } else {
1923 (void) div_mp (p, z, u, v, digits);
1924 (void) mul_mp (p, z, z, z, digits);
1925 (void) add_mp (p, z, t, z, digits);
1926 (void) sqrt_mp (p, z, z, digits);
1927 (void) mul_mp (p, z, v, z, digits);
1928 }
1929 }
1930 stack_pointer = pop_sp;
1931 return (z);
1932 }
1933
1934 /**
1935 @brief Set "z" to exp ("x").
1936 @param p Node in syntax tree.
1937 @param z Multiprecision number.
1938 @param x Multiprecision number.
1939 @param digits Precision in mp-digits.
1940 @return Result "z".
1941 **/
1942
1943 MP_T *
exp_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)1944 exp_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
1945 {
1946 /* Argument is reduced by using exp (z / (2 ** n)) ** (2 ** n) = exp(z) */
1947 int m, n, pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
1948 MP_T *x_g, *sum, *a68g_pow, *fac, *tmp;
1949 BOOL_T iterate;
1950 if (MP_DIGIT (x, 1) == 0) {
1951 (void) set_mp_short (z, (MP_T) 1, 0, digits);
1952 return (z);
1953 }
1954 STACK_MP (x_g, p, digits_g);
1955 STACK_MP (sum, p, digits_g);
1956 STACK_MP (a68g_pow, p, digits_g);
1957 STACK_MP (fac, p, digits_g);
1958 STACK_MP (tmp, p, digits_g);
1959 (void) lengthen_mp (p, x_g, digits_g, x, digits);
1960 m = 0;
1961 /* Scale x down */
1962 while (eps_mp (x_g, digits_g)) {
1963 m++;
1964 (void) half_mp (p, x_g, x_g, digits_g);
1965 }
1966 /* Calculate Taylor sum
1967 exp (z) = 1 + z / 1 ! + z ** 2 / 2 ! + .. */
1968 (void) set_mp_short (sum, (MP_T) 1, 0, digits_g);
1969 (void) add_mp (p, sum, sum, x_g, digits_g);
1970 (void) mul_mp (p, a68g_pow, x_g, x_g, digits_g);
1971 #if (MP_RADIX == DEFAULT_MP_RADIX)
1972 (void) half_mp (p, tmp, a68g_pow, digits_g);
1973 (void) add_mp (p, sum, sum, tmp, digits_g);
1974 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1975 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 6, digits_g);
1976 (void) add_mp (p, sum, sum, tmp, digits_g);
1977 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1978 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 24, digits_g);
1979 (void) add_mp (p, sum, sum, tmp, digits_g);
1980 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1981 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 120, digits_g);
1982 (void) add_mp (p, sum, sum, tmp, digits_g);
1983 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1984 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 720, digits_g);
1985 (void) add_mp (p, sum, sum, tmp, digits_g);
1986 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1987 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 5040, digits_g);
1988 (void) add_mp (p, sum, sum, tmp, digits_g);
1989 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1990 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 40320, digits_g);
1991 (void) add_mp (p, sum, sum, tmp, digits_g);
1992 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1993 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 362880, digits_g);
1994 (void) add_mp (p, sum, sum, tmp, digits_g);
1995 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
1996 (void) set_mp_short (fac, (MP_T) (MP_T) 3628800, 0, digits_g);
1997 n = 10;
1998 #else
1999 (void) set_mp_short (fac, (MP_T) 2, 0, digits_g);
2000 n = 2;
2001 #endif
2002 iterate = (BOOL_T) (MP_DIGIT (a68g_pow, 1) != 0);
2003 while (iterate) {
2004 (void) div_mp (p, tmp, a68g_pow, fac, digits_g);
2005 if (MP_EXPONENT (tmp) <= (MP_EXPONENT (sum) - digits_g)) {
2006 iterate = A68_FALSE;
2007 } else {
2008 (void) add_mp (p, sum, sum, tmp, digits_g);
2009 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2010 n++;
2011 (void) mul_mp_digit (p, fac, fac, (MP_T) n, digits_g);
2012 }
2013 }
2014 /* Square exp (x) up */
2015 while (m--) {
2016 (void) mul_mp (p, sum, sum, sum, digits_g);
2017 }
2018 (void) shorten_mp (p, z, digits, sum, digits_g);
2019 /* Exit */
2020 stack_pointer = pop_sp;
2021 return (z);
2022 }
2023
2024 /**
2025 @brief Set "z" to exp ("x") - 1, assuming "x" to be close to 0.
2026 @param p Node in syntax tree.
2027 @param z Multiprecision number.
2028 @param x Multiprecision number.
2029 @param digits Precision in mp-digits.
2030 @return Result "z".
2031 **/
2032
2033 MP_T *
expm1_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2034 expm1_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2035 {
2036 int n, pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2037 MP_T *x_g, *sum, *a68g_pow, *fac, *tmp;
2038 BOOL_T iterate;
2039 if (MP_DIGIT (x, 1) == 0) {
2040 (void) set_mp_short (z, (MP_T) 1, 0, digits);
2041 return (z);
2042 }
2043 STACK_MP (x_g, p, digits_g);
2044 STACK_MP (sum, p, digits_g);
2045 STACK_MP (a68g_pow, p, digits_g);
2046 STACK_MP (fac, p, digits_g);
2047 STACK_MP (tmp, p, digits_g);
2048 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2049 /* Calculate Taylor sum expm1 (z) = z / 1 ! + z ** 2 / 2 ! + .. */
2050 SET_MP_ZERO (sum, digits_g);
2051 (void) add_mp (p, sum, sum, x_g, digits_g);
2052 (void) mul_mp (p, a68g_pow, x_g, x_g, digits_g);
2053 #if (MP_RADIX == DEFAULT_MP_RADIX)
2054 (void) half_mp (p, tmp, a68g_pow, digits_g);
2055 (void) add_mp (p, sum, sum, tmp, digits_g);
2056 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2057 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 6, digits_g);
2058 (void) add_mp (p, sum, sum, tmp, digits_g);
2059 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2060 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 24, digits_g);
2061 (void) add_mp (p, sum, sum, tmp, digits_g);
2062 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2063 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 120, digits_g);
2064 (void) add_mp (p, sum, sum, tmp, digits_g);
2065 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2066 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 720, digits_g);
2067 (void) add_mp (p, sum, sum, tmp, digits_g);
2068 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2069 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 5040, digits_g);
2070 (void) add_mp (p, sum, sum, tmp, digits_g);
2071 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2072 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 40320, digits_g);
2073 (void) add_mp (p, sum, sum, tmp, digits_g);
2074 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2075 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 362880, digits_g);
2076 (void) add_mp (p, sum, sum, tmp, digits_g);
2077 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2078 (void) set_mp_short (fac, (MP_T) (MP_T) 3628800, 0, digits_g);
2079 n = 10;
2080 #else
2081 (void) set_mp_short (fac, (MP_T) 2, 0, digits_g);
2082 n = 2;
2083 #endif
2084 iterate = (BOOL_T) (MP_DIGIT (a68g_pow, 1) != 0);
2085 while (iterate) {
2086 (void) div_mp (p, tmp, a68g_pow, fac, digits_g);
2087 if (MP_EXPONENT (tmp) <= (MP_EXPONENT (sum) - digits_g)) {
2088 iterate = A68_FALSE;
2089 } else {
2090 (void) add_mp (p, sum, sum, tmp, digits_g);
2091 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2092 n++;
2093 (void) mul_mp_digit (p, fac, fac, (MP_T) n, digits_g);
2094 }
2095 }
2096 (void) shorten_mp (p, z, digits, sum, digits_g);
2097 /* Exit */
2098 stack_pointer = pop_sp;
2099 return (z);
2100 }
2101
2102 /**
2103 @brief Ln scale with digits precision.
2104 @param p Node in syntax tree.
2105 @param z Multiprecision number.
2106 @param digits Precision in mp-digits.
2107 @return Result "z".
2108 **/
2109
2110 MP_T *
mp_ln_scale(NODE_T * p,MP_T * z,int digits)2111 mp_ln_scale (NODE_T * p, MP_T * z, int digits)
2112 {
2113 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2114 MP_T *z_g;
2115 STACK_MP (z_g, p, digits_g);
2116 /* First see if we can restore a previous calculation */
2117 if (digits_g <= mp_ln_scale_size) {
2118 MOVE_MP (z_g, ref_mp_ln_scale, digits_g);
2119 } else {
2120 /* No luck with the kept value, we generate a longer one */
2121 (void) set_mp_short (z_g, (MP_T) 1, 1, digits_g);
2122 (void) ln_mp (p, z_g, z_g, digits_g);
2123 ref_mp_ln_scale = (MP_T *) get_heap_space ((unsigned) SIZE_MP (digits_g));
2124 MOVE_MP (ref_mp_ln_scale, z_g, digits_g);
2125 mp_ln_scale_size = digits_g;
2126 }
2127 (void) shorten_mp (p, z, digits, z_g, digits_g);
2128 stack_pointer = pop_sp;
2129 return (z);
2130 }
2131
2132 /**
2133 @brief Ln 10 with digits precision.
2134 @param p Node in syntax tree.
2135 @param z Multiprecision number.
2136 @param digits Precision in mp-digits.
2137 @return Result "z".
2138 **/
2139
2140 MP_T *
mp_ln_10(NODE_T * p,MP_T * z,int digits)2141 mp_ln_10 (NODE_T * p, MP_T * z, int digits)
2142 {
2143 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2144 MP_T *z_g;
2145 STACK_MP (z_g, p, digits_g);
2146 /* First see if we can restore a previous calculation */
2147 if (digits_g <= mp_ln_10_size) {
2148 MOVE_MP (z_g, ref_mp_ln_10, digits_g);
2149 } else {
2150 /* No luck with the kept value, we generate a longer one */
2151 (void) set_mp_short (z_g, (MP_T) 10, 0, digits_g);
2152 (void) ln_mp (p, z_g, z_g, digits_g);
2153 ref_mp_ln_10 = (MP_T *) get_heap_space ((unsigned) SIZE_MP (digits_g));
2154 MOVE_MP (ref_mp_ln_10, z_g, digits_g);
2155 mp_ln_10_size = digits_g;
2156 }
2157 (void) shorten_mp (p, z, digits, z_g, digits_g);
2158 stack_pointer = pop_sp;
2159 return (z);
2160 }
2161
2162 /**
2163 @brief Set "z" to ln ("x").
2164 @param p Node in syntax tree.
2165 @param z Multiprecision number.
2166 @param x Multiprecision number.
2167 @param digits Precision in mp-digits.
2168 @return Result "z".
2169 **/
2170
2171 MP_T *
ln_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2172 ln_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2173 {
2174 /* Depending on the argument we choose either Taylor or Newton */
2175 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2176 BOOL_T negative, scale;
2177 MP_T *x_g, *z_g, expo = 0;
2178 if (MP_DIGIT (x, 1) <= 0) {
2179 errno = EDOM;
2180 return (NO_MP);
2181 }
2182 STACK_MP (x_g, p, digits_g);
2183 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2184 STACK_MP (z_g, p, digits_g);
2185 /* We use ln (1 / x) = - ln (x) */
2186 negative = (BOOL_T) (MP_EXPONENT (x_g) < 0);
2187 if (negative) {
2188 (void) rec_mp (p, x_g, x_g, digits);
2189 }
2190 /* We want correct results for extreme arguments. We scale when "x_g" exceeds
2191 "MP_RADIX ** +- 2", using ln (x * MP_RADIX ** n) = ln (x) + n * ln (MP_RADIX).*/
2192 scale = (BOOL_T) (ABS (MP_EXPONENT (x_g)) >= 2);
2193 if (scale) {
2194 expo = MP_EXPONENT (x_g);
2195 MP_EXPONENT (x_g) = (MP_T) 0;
2196 }
2197 if (MP_EXPONENT (x_g) == 0 && MP_DIGIT (x_g, 1) == 1 && MP_DIGIT (x_g, 2) == 0) {
2198 /* Taylor sum for x close to unity.
2199 ln (x) = (x - 1) - (x - 1) ** 2 / 2 + (x - 1) ** 3 / 3 - ...
2200 This is faster for small x and avoids cancellation */
2201 MP_T *one, *tmp, *a68g_pow;
2202 int n = 2;
2203 BOOL_T iterate;
2204 STACK_MP (one, p, digits_g);
2205 STACK_MP (tmp, p, digits_g);
2206 STACK_MP (a68g_pow, p, digits_g);
2207 (void) set_mp_short (one, (MP_T) 1, 0, digits_g);
2208 (void) sub_mp (p, x_g, x_g, one, digits_g);
2209 (void) mul_mp (p, a68g_pow, x_g, x_g, digits_g);
2210 MOVE_MP (z_g, x_g, digits_g);
2211 iterate = (BOOL_T) (MP_DIGIT (a68g_pow, 1) != 0);
2212 while (iterate) {
2213 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) n, digits_g);
2214 if (MP_EXPONENT (tmp) <= (MP_EXPONENT (z_g) - digits_g)) {
2215 iterate = A68_FALSE;
2216 } else {
2217 MP_DIGIT (tmp, 1) = (n % 2 == 0 ? -MP_DIGIT (tmp, 1) : MP_DIGIT (tmp, 1));
2218 (void) add_mp (p, z_g, z_g, tmp, digits_g);
2219 (void) mul_mp (p, a68g_pow, a68g_pow, x_g, digits_g);
2220 n++;
2221 }
2222 }
2223 } else {
2224 /* Newton's method: x<n+1> = x<n> - 1 + a / exp (x<n>) */
2225 MP_T *tmp, *z_0, *one;
2226 int decimals;
2227 STACK_MP (tmp, p, digits_g);
2228 STACK_MP (one, p, digits_g);
2229 STACK_MP (z_0, p, digits_g);
2230 (void) set_mp_short (one, (MP_T) 1, 0, digits_g);
2231 SET_MP_ZERO (z_0, digits_g);
2232 /* Construct an estimate */
2233 (void) real_to_mp (p, z_g, log (mp_to_real (p, x_g, digits_g)), digits_g);
2234 decimals = DOUBLE_ACCURACY;
2235 do {
2236 int digits_h;
2237 decimals <<= 1;
2238 digits_h = MINIMUM (1 + decimals / LOG_MP_BASE, digits_g);
2239 (void) exp_mp (p, tmp, z_g, digits_h);
2240 (void) div_mp (p, tmp, x_g, tmp, digits_h);
2241 (void) sub_mp (p, z_g, z_g, one, digits_h);
2242 (void) add_mp (p, z_g, z_g, tmp, digits_h);
2243 } while (decimals < digits_g * LOG_MP_BASE);
2244 }
2245 /* Inverse scaling */
2246 if (scale) {
2247 /* ln (x * MP_RADIX ** n) = ln (x) + n * ln (MP_RADIX) */
2248 MP_T *ln_base;
2249 STACK_MP (ln_base, p, digits_g);
2250 (void) mp_ln_scale (p, ln_base, digits_g);
2251 (void) mul_mp_digit (p, ln_base, ln_base, (MP_T) expo, digits_g);
2252 (void) add_mp (p, z_g, z_g, ln_base, digits_g);
2253 }
2254 if (negative) {
2255 MP_DIGIT (z_g, 1) = -MP_DIGIT (z_g, 1);
2256 }
2257 (void) shorten_mp (p, z, digits, z_g, digits_g);
2258 /* Exit */
2259 stack_pointer = pop_sp;
2260 return (z);
2261 }
2262
2263 /**
2264 @brief Set "z" to log ("x").
2265 @param p Node in syntax tree.
2266 @param z Multiprecision number.
2267 @param x Multiprecision number.
2268 @param digits Precision in mp-digits.
2269 @return Result "z".
2270 **/
2271
2272 MP_T *
log_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2273 log_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2274 {
2275 int pop_sp = stack_pointer;
2276 MP_T *ln_10;
2277 STACK_MP (ln_10, p, digits);
2278 if (ln_mp (p, z, x, digits) == NO_MP) {
2279 errno = EDOM;
2280 return (NO_MP);
2281 }
2282 (void) mp_ln_10 (p, ln_10, digits);
2283 (void) div_mp (p, z, z, ln_10, digits);
2284 stack_pointer = pop_sp;
2285 return (z);
2286 }
2287
2288 /**
2289 @brief Set "sh" and "ch" to sinh ("z") and cosh ("z") respectively.
2290 @param p Node in syntax tree.
2291 @param sh Multiprecision number.
2292 @param ch Multiprecision number.
2293 @param z Multiprecision number.
2294 @param digits Precision in mp-digits.
2295 @return Result "z".
2296 **/
2297
2298 MP_T *
hyp_mp(NODE_T * p,MP_T * sh,MP_T * ch,MP_T * z,int digits)2299 hyp_mp (NODE_T * p, MP_T * sh, MP_T * ch, MP_T * z, int digits)
2300 {
2301 ADDR_T pop_sp = stack_pointer;
2302 MP_T *x_g, *y_g, *z_g;
2303 STACK_MP (x_g, p, digits);
2304 STACK_MP (y_g, p, digits);
2305 STACK_MP (z_g, p, digits);
2306 MOVE_MP (z_g, z, digits);
2307 (void) exp_mp (p, x_g, z_g, digits);
2308 (void) rec_mp (p, y_g, x_g, digits);
2309 (void) add_mp (p, ch, x_g, y_g, digits);
2310 /* Avoid cancellation for sinh */
2311 if ((MP_DIGIT (x_g, 1) == 1 && MP_DIGIT (x_g, 2) == 0) || (MP_DIGIT (y_g, 1) == 1 && MP_DIGIT (y_g, 2) == 0)) {
2312 (void) expm1_mp (p, x_g, z_g, digits);
2313 MP_DIGIT (z_g, 1) = -MP_DIGIT (z_g, 1);
2314 (void) expm1_mp (p, y_g, z_g, digits);
2315 }
2316 (void) sub_mp (p, sh, x_g, y_g, digits);
2317 (void) half_mp (p, sh, sh, digits);
2318 (void) half_mp (p, ch, ch, digits);
2319 stack_pointer = pop_sp;
2320 return (z);
2321 }
2322
2323 /**
2324 @brief Set "z" to sinh ("x").
2325 @param p Node in syntax tree.
2326 @param z Multiprecision number.
2327 @param x Multiprecision number.
2328 @param digits Precision in mp-digits.
2329 @return Result "z".
2330 **/
2331
2332 MP_T *
sinh_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2333 sinh_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2334 {
2335 ADDR_T pop_sp = stack_pointer;
2336 int digits_g = FUN_DIGITS (digits);
2337 MP_T *x_g, *y_g, *z_g;
2338 STACK_MP (x_g, p, digits_g);
2339 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2340 STACK_MP (y_g, p, digits_g);
2341 STACK_MP (z_g, p, digits_g);
2342 (void) hyp_mp (p, z_g, y_g, x_g, digits_g);
2343 (void) shorten_mp (p, z, digits, z_g, digits_g);
2344 stack_pointer = pop_sp;
2345 return (z);
2346 }
2347
2348 /**
2349 @brief Set "z" to asinh ("x").
2350 @param p Node in syntax tree.
2351 @param z Multiprecision number.
2352 @param x Multiprecision number.
2353 @param digits Precision in mp-digits.
2354 @return Result "z".
2355 **/
2356
2357 MP_T *
asinh_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2358 asinh_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2359 {
2360 if (IS_ZERO_MP (x)) {
2361 SET_MP_ZERO (z, digits);
2362 return (z);
2363 } else {
2364 ADDR_T pop_sp = stack_pointer;
2365 int digits_g;
2366 MP_T *x_g, *y_g, *z_g;
2367 if (MP_EXPONENT (x) >= -1) {
2368 digits_g = FUN_DIGITS (digits);
2369 } else {
2370 /* Extra precision when x^2+1 gets close to 1 */
2371 digits_g = 2 * FUN_DIGITS (digits);
2372 }
2373 STACK_MP (x_g, p, digits_g);
2374 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2375 STACK_MP (y_g, p, digits_g);
2376 STACK_MP (z_g, p, digits_g);
2377 (void) mul_mp (p, z_g, x_g, x_g, digits_g);
2378 (void) set_mp_short (y_g, (MP_T) 1, 0, digits_g);
2379 (void) add_mp (p, y_g, z_g, y_g, digits_g);
2380 (void) sqrt_mp (p, y_g, y_g, digits_g);
2381 (void) add_mp (p, y_g, y_g, x_g, digits_g);
2382 (void) ln_mp (p, z_g, y_g, digits_g);
2383 if (IS_ZERO_MP (z_g)) {
2384 MOVE_MP (z, x, digits);
2385 } else {
2386 (void) shorten_mp (p, z, digits, z_g, digits_g);
2387 }
2388 stack_pointer = pop_sp;
2389 return (z);
2390 }
2391 }
2392
2393 /**
2394 @brief Set "z" to cosh ("x").
2395 @param p Node in syntax tree.
2396 @param z Multiprecision number.
2397 @param x Multiprecision number.
2398 @param digits Precision in mp-digits.
2399 @return Result "z".
2400 **/
2401
2402 MP_T *
cosh_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2403 cosh_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2404 {
2405 ADDR_T pop_sp = stack_pointer;
2406 int digits_g = FUN_DIGITS (digits);
2407 MP_T *x_g, *y_g, *z_g;
2408 STACK_MP (x_g, p, digits_g);
2409 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2410 STACK_MP (y_g, p, digits_g);
2411 STACK_MP (z_g, p, digits_g);
2412 (void) hyp_mp (p, y_g, z_g, x_g, digits_g);
2413 (void) shorten_mp (p, z, digits, z_g, digits_g);
2414 stack_pointer = pop_sp;
2415 return (z);
2416 }
2417
2418 /**
2419 @brief Set "z" to acosh ("x").
2420 @param p Node in syntax tree.
2421 @param z Multiprecision number.
2422 @param x Multiprecision number.
2423 @param digits Precision in mp-digits.
2424 @return Result "z".
2425 **/
2426
2427 MP_T *
acosh_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2428 acosh_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2429 {
2430 ADDR_T pop_sp = stack_pointer;
2431 int digits_g;
2432 MP_T *x_g, *y_g, *z_g;
2433 if (MP_DIGIT (x, 1) == 1 && MP_DIGIT (x, 2) == 0) {
2434 /* Extra precision when x^2-1 gets close to 0 */
2435 digits_g = 2 * FUN_DIGITS (digits);
2436 } else {
2437 digits_g = FUN_DIGITS (digits);
2438 }
2439 STACK_MP (x_g, p, digits_g);
2440 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2441 STACK_MP (y_g, p, digits_g);
2442 STACK_MP (z_g, p, digits_g);
2443 (void) mul_mp (p, z_g, x_g, x_g, digits_g);
2444 (void) set_mp_short (y_g, (MP_T) 1, 0, digits_g);
2445 (void) sub_mp (p, y_g, z_g, y_g, digits_g);
2446 (void) sqrt_mp (p, y_g, y_g, digits_g);
2447 (void) add_mp (p, y_g, y_g, x_g, digits_g);
2448 (void) ln_mp (p, z_g, y_g, digits_g);
2449 (void) shorten_mp (p, z, digits, z_g, digits_g);
2450 stack_pointer = pop_sp;
2451 return (z);
2452 }
2453
2454 /**
2455 @brief Set "z" to tanh ("x").
2456 @param p Node in syntax tree.
2457 @param z Multiprecision number.
2458 @param x Multiprecision number.
2459 @param digits Precision in mp-digits.
2460 @return Result "z".
2461 **/
2462
2463 MP_T *
tanh_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2464 tanh_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2465 {
2466 ADDR_T pop_sp = stack_pointer;
2467 int digits_g = FUN_DIGITS (digits);
2468 MP_T *x_g, *y_g, *z_g;
2469 STACK_MP (x_g, p, digits_g);
2470 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2471 STACK_MP (y_g, p, digits_g);
2472 STACK_MP (z_g, p, digits_g);
2473 (void) hyp_mp (p, y_g, z_g, x_g, digits_g);
2474 (void) div_mp (p, z_g, y_g, z_g, digits_g);
2475 (void) shorten_mp (p, z, digits, z_g, digits_g);
2476 stack_pointer = pop_sp;
2477 return (z);
2478 }
2479
2480 /**
2481 @brief Set "z" to atanh ("x").
2482 @param p Node in syntax tree.
2483 @param z Multiprecision number.
2484 @param x Multiprecision number.
2485 @param digits Precision in mp-digits.
2486 @return Result "z".
2487 **/
2488
2489 MP_T *
atanh_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2490 atanh_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2491 {
2492 ADDR_T pop_sp = stack_pointer;
2493 int digits_g = FUN_DIGITS (digits);
2494 MP_T *x_g, *y_g, *z_g;
2495 STACK_MP (x_g, p, digits_g);
2496 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2497 STACK_MP (y_g, p, digits_g);
2498 STACK_MP (z_g, p, digits_g);
2499 (void) set_mp_short (y_g, (MP_T) 1, 0, digits_g);
2500 (void) add_mp (p, z_g, y_g, x_g, digits_g);
2501 (void) sub_mp (p, y_g, y_g, x_g, digits_g);
2502 (void) div_mp (p, y_g, z_g, y_g, digits_g);
2503 (void) ln_mp (p, z_g, y_g, digits_g);
2504 (void) half_mp (p, z_g, z_g, digits_g);
2505 (void) shorten_mp (p, z, digits, z_g, digits_g);
2506 stack_pointer = pop_sp;
2507 return (z);
2508 }
2509
2510 /**
2511 @brief Return "pi" with "digits" precision, using Borwein & Borwein AGM.
2512 @param p Node in syntax tree.
2513 @param api Multiprecision number.
2514 @param mult Small multiplier.
2515 @param digits Precision in mp-digits.
2516 @return Result "api".
2517 **/
2518
2519 MP_T *
mp_pi(NODE_T * p,MP_T * api,int mult,int digits)2520 mp_pi (NODE_T * p, MP_T * api, int mult, int digits)
2521 {
2522 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2523 BOOL_T iterate;
2524 MP_T *pi_g, *one, *two, *x_g, *y_g, *u_g, *v_g;
2525 STACK_MP (pi_g, p, digits_g);
2526 /* First see if we can restore a previous calculation */
2527 if (digits_g <= mp_pi_size) {
2528 MOVE_MP (pi_g, ref_mp_pi, digits_g);
2529 } else {
2530 /* No luck with the kept value, hence we generate a longer "pi".
2531 Calculate "pi" using the Borwein & Borwein AGM algorithm.
2532 This AGM doubles the numbers of digits at every pass */
2533 STACK_MP (one, p, digits_g);
2534 STACK_MP (two, p, digits_g);
2535 STACK_MP (x_g, p, digits_g);
2536 STACK_MP (y_g, p, digits_g);
2537 STACK_MP (u_g, p, digits_g);
2538 STACK_MP (v_g, p, digits_g);
2539 (void) set_mp_short (one, (MP_T) 1, 0, digits_g);
2540 (void) set_mp_short (two, (MP_T) 2, 0, digits_g);
2541 (void) set_mp_short (x_g, (MP_T) 2, 0, digits_g);
2542 (void) sqrt_mp (p, x_g, x_g, digits_g);
2543 (void) add_mp (p, pi_g, x_g, two, digits_g);
2544 (void) sqrt_mp (p, y_g, x_g, digits_g);
2545 iterate = A68_TRUE;
2546 while (iterate) {
2547 /* New x */
2548 (void) sqrt_mp (p, u_g, x_g, digits_g);
2549 (void) div_mp (p, v_g, one, u_g, digits_g);
2550 (void) add_mp (p, u_g, u_g, v_g, digits_g);
2551 (void) half_mp (p, x_g, u_g, digits_g);
2552 /* New pi */
2553 (void) add_mp (p, u_g, x_g, one, digits_g);
2554 (void) add_mp (p, v_g, y_g, one, digits_g);
2555 (void) div_mp (p, u_g, u_g, v_g, digits_g);
2556 (void) mul_mp (p, v_g, pi_g, u_g, digits_g);
2557 /* Done yet? */
2558 if (same_mp (p, v_g, pi_g, digits_g)) {
2559 iterate = A68_FALSE;
2560 } else {
2561 MOVE_MP (pi_g, v_g, digits_g);
2562 /* New y */
2563 (void) sqrt_mp (p, u_g, x_g, digits_g);
2564 (void) div_mp (p, v_g, one, u_g, digits_g);
2565 (void) mul_mp (p, u_g, y_g, u_g, digits_g);
2566 (void) add_mp (p, u_g, u_g, v_g, digits_g);
2567 (void) add_mp (p, v_g, y_g, one, digits_g);
2568 (void) div_mp (p, y_g, u_g, v_g, digits_g);
2569 }
2570 }
2571 /* Keep the result for future restore */
2572 ref_mp_pi = (MP_T *) get_heap_space ((unsigned) SIZE_MP (digits_g));
2573 MOVE_MP (ref_mp_pi, pi_g, digits_g);
2574 mp_pi_size = digits_g;
2575 }
2576 switch (mult) {
2577 case MP_PI:
2578 {
2579 break;
2580 }
2581 case MP_TWO_PI:
2582 {
2583 (void) mul_mp_digit (p, pi_g, pi_g, (MP_T) 2, digits_g);
2584 break;
2585 }
2586 case MP_HALF_PI:
2587 {
2588 (void) half_mp (p, pi_g, pi_g, digits_g);
2589 break;
2590 }
2591 }
2592 (void) shorten_mp (p, api, digits, pi_g, digits_g);
2593 stack_pointer = pop_sp;
2594 return (api);
2595 }
2596
2597 /**
2598 @brief Set "z" to sin ("x").
2599 @param p Node in syntax tree.
2600 @param z Multiprecision number.
2601 @param x Multiprecision number.
2602 @param digits Precision in mp-digits.
2603 @return Result "z".
2604 **/
2605
2606 MP_T *
sin_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2607 sin_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2608 {
2609 /* Use triple-angle relation to reduce argument */
2610 int pop_sp = stack_pointer, m, n, digits_g = FUN_DIGITS (digits);
2611 BOOL_T flip, negative, iterate, even;
2612 MP_T *x_g, *pi, *tpi, *hpi, *sqr, *tmp, *a68g_pow, *fac, *z_g;
2613 /* We will use "pi" */
2614 STACK_MP (pi, p, digits_g);
2615 STACK_MP (tpi, p, digits_g);
2616 STACK_MP (hpi, p, digits_g);
2617 (void) mp_pi (p, pi, MP_PI, digits_g);
2618 (void) mp_pi (p, tpi, MP_TWO_PI, digits_g);
2619 (void) mp_pi (p, hpi, MP_HALF_PI, digits_g);
2620 /* Argument reduction (1): sin (x) = sin (x mod 2 pi) */
2621 STACK_MP (x_g, p, digits_g);
2622 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2623 (void) mod_mp (p, x_g, x_g, tpi, digits_g);
2624 /* Argument reduction (2): sin (-x) = sin (x)
2625 sin (x) = - sin (x - pi); pi < x <= 2 pi
2626 sin (x) = sin (pi - x); pi / 2 < x <= pi */
2627 negative = (BOOL_T) (MP_DIGIT (x_g, 1) < 0);
2628 if (negative) {
2629 MP_DIGIT (x_g, 1) = -MP_DIGIT (x_g, 1);
2630 }
2631 STACK_MP (tmp, p, digits_g);
2632 (void) sub_mp (p, tmp, x_g, pi, digits_g);
2633 flip = (BOOL_T) (MP_DIGIT (tmp, 1) > 0);
2634 if (flip) { /* x > pi */
2635 (void) sub_mp (p, x_g, x_g, pi, digits_g);
2636 }
2637 (void) sub_mp (p, tmp, x_g, hpi, digits_g);
2638 if (MP_DIGIT (tmp, 1) > 0) { /* x > pi / 2 */
2639 (void) sub_mp (p, x_g, pi, x_g, digits_g);
2640 }
2641 /* Argument reduction (3): (follows from De Moivre's theorem)
2642 sin (3x) = sin (x) * (3 - 4 sin ^ 2 (x)) */
2643 m = 0;
2644 while (eps_mp (x_g, digits_g)) {
2645 m++;
2646 (void) div_mp_digit (p, x_g, x_g, (MP_T) 3, digits_g);
2647 }
2648 /* Taylor sum */
2649 STACK_MP (sqr, p, digits_g);
2650 STACK_MP (a68g_pow, p, digits_g);
2651 STACK_MP (fac, p, digits_g);
2652 STACK_MP (z_g, p, digits_g);
2653 (void) mul_mp (p, sqr, x_g, x_g, digits_g); /* sqr = x ** 2 */
2654 (void) mul_mp (p, a68g_pow, sqr, x_g, digits_g); /* pow = x ** 3 */
2655 MOVE_MP (z_g, x_g, digits_g);
2656 #if (MP_RADIX == DEFAULT_MP_RADIX)
2657 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 6, digits_g);
2658 (void) sub_mp (p, z_g, z_g, tmp, digits_g);
2659 (void) mul_mp (p, a68g_pow, a68g_pow, sqr, digits_g);
2660 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 120, digits_g);
2661 (void) add_mp (p, z_g, z_g, tmp, digits_g);
2662 (void) mul_mp (p, a68g_pow, a68g_pow, sqr, digits_g);
2663 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) 5040, digits_g);
2664 (void) sub_mp (p, z_g, z_g, tmp, digits_g);
2665 (void) mul_mp (p, a68g_pow, a68g_pow, sqr, digits_g);
2666 (void) set_mp_short (fac, (MP_T) 362880, 0, digits_g);
2667 n = 9;
2668 even = A68_TRUE;
2669 #else
2670 (void) set_mp_short (fac, (MP_T) 6, 0, digits_g);
2671 n = 3;
2672 even = A68_FALSE;
2673 #endif
2674 iterate = (BOOL_T) (MP_DIGIT (a68g_pow, 1) != 0);
2675 while (iterate) {
2676 (void) div_mp (p, tmp, a68g_pow, fac, digits_g);
2677 if (MP_EXPONENT (tmp) <= (MP_EXPONENT (z_g) - digits_g)) {
2678 iterate = A68_FALSE;
2679 } else {
2680 if (even) {
2681 (void) add_mp (p, z_g, z_g, tmp, digits_g);
2682 even = A68_FALSE;
2683 } else {
2684 (void) sub_mp (p, z_g, z_g, tmp, digits_g);
2685 even = A68_TRUE;
2686 }
2687 (void) mul_mp (p, a68g_pow, a68g_pow, sqr, digits_g);
2688 (void) mul_mp_digit (p, fac, fac, (MP_T) (++n), digits_g);
2689 (void) mul_mp_digit (p, fac, fac, (MP_T) (++n), digits_g);
2690 }
2691 }
2692 /* Inverse scaling using sin (3x) = sin (x) * (3 - 4 sin ** 2 (x))
2693 Use existing mp's for intermediates */
2694 (void) set_mp_short (fac, (MP_T) 3, 0, digits_g);
2695 while (m--) {
2696 (void) mul_mp (p, a68g_pow, z_g, z_g, digits_g);
2697 (void) mul_mp_digit (p, a68g_pow, a68g_pow, (MP_T) 4, digits_g);
2698 (void) sub_mp (p, a68g_pow, fac, a68g_pow, digits_g);
2699 (void) mul_mp (p, z_g, a68g_pow, z_g, digits_g);
2700 }
2701 (void) shorten_mp (p, z, digits, z_g, digits_g);
2702 if (negative ^ flip) {
2703 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
2704 }
2705 /* Exit */
2706 stack_pointer = pop_sp;
2707 return (z);
2708 }
2709
2710 /**
2711 @brief Set "z" to cos ("x").
2712 @param p Node in syntax tree.
2713 @param z Multiprecision number.
2714 @param x Multiprecision number.
2715 @param digits Precision in mp-digits.
2716 @return Result "z".
2717 **/
2718
2719 MP_T *
cos_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2720 cos_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2721 {
2722 /*
2723 Use cos (x) = sin (pi / 2 - x).
2724 Compute x mod 2 pi before subtracting to avoid cancellation.
2725 */
2726 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2727 MP_T *hpi, *tpi, *x_g, *y;
2728 STACK_MP (hpi, p, digits_g);
2729 STACK_MP (tpi, p, digits_g);
2730 STACK_MP (x_g, p, digits_g);
2731 STACK_MP (y, p, digits);
2732 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2733 (void) mp_pi (p, hpi, MP_HALF_PI, digits_g);
2734 (void) mp_pi (p, tpi, MP_TWO_PI, digits_g);
2735 (void) mod_mp (p, x_g, x_g, tpi, digits_g);
2736 (void) sub_mp (p, x_g, hpi, x_g, digits_g);
2737 (void) shorten_mp (p, y, digits, x_g, digits_g);
2738 (void) sin_mp (p, z, y, digits);
2739 stack_pointer = pop_sp;
2740 return (z);
2741 }
2742
2743 /**
2744 @brief Set "z" to tan ("x").
2745 @param p Node in syntax tree.
2746 @param z Multiprecision number.
2747 @param x Multiprecision number.
2748 @param digits Precision in mp-digits.
2749 @return Result "z".
2750 **/
2751
2752 MP_T *
tan_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2753 tan_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2754 {
2755 /* Use tan (x) = sin (x) / sqrt (1 - sin ^ 2 (x)) */
2756 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2757 MP_T *sns, *cns, *one, *pi, *hpi, *x_g, *y_g;
2758 BOOL_T negate;
2759 STACK_MP (one, p, digits);
2760 STACK_MP (pi, p, digits_g);
2761 STACK_MP (hpi, p, digits_g);
2762 STACK_MP (x_g, p, digits_g);
2763 STACK_MP (y_g, p, digits_g);
2764 STACK_MP (sns, p, digits);
2765 STACK_MP (cns, p, digits);
2766 /* Argument mod pi */
2767 (void) mp_pi (p, pi, MP_PI, digits_g);
2768 (void) mp_pi (p, hpi, MP_HALF_PI, digits_g);
2769 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2770 (void) mod_mp (p, x_g, x_g, pi, digits_g);
2771 if (MP_DIGIT (x_g, 1) >= 0) {
2772 (void) sub_mp (p, y_g, x_g, hpi, digits_g);
2773 negate = (BOOL_T) (MP_DIGIT (y_g, 1) > 0);
2774 } else {
2775 (void) add_mp (p, y_g, x_g, hpi, digits_g);
2776 negate = (BOOL_T) (MP_DIGIT (y_g, 1) < 0);
2777 }
2778 (void) shorten_mp (p, x, digits, x_g, digits_g);
2779 /* tan(x) = sin(x) / sqrt (1 - sin ** 2 (x)) */
2780 (void) sin_mp (p, sns, x, digits);
2781 (void) set_mp_short (one, (MP_T) 1, 0, digits);
2782 (void) mul_mp (p, cns, sns, sns, digits);
2783 (void) sub_mp (p, cns, one, cns, digits);
2784 (void) sqrt_mp (p, cns, cns, digits);
2785 if (div_mp (p, z, sns, cns, digits) == NO_MP) {
2786 errno = EDOM;
2787 stack_pointer = pop_sp;
2788 return (NO_MP);
2789 }
2790 stack_pointer = pop_sp;
2791 if (negate) {
2792 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
2793 }
2794 return (z);
2795 }
2796
2797 /**
2798 @brief Set "z" to arcsin ("x").
2799 @param p Node in syntax tree.
2800 @param z Multiprecision number.
2801 @param x Multiprecision number.
2802 @param digits Precision in mp-digits.
2803 @return Result "z".
2804 **/
2805
2806 MP_T *
asin_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2807 asin_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2808 {
2809 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2810 MP_T *one, *x_g, *y, *z_g;
2811 STACK_MP (y, p, digits);
2812 STACK_MP (x_g, p, digits_g);
2813 STACK_MP (z_g, p, digits_g);
2814 STACK_MP (one, p, digits_g);
2815 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2816 (void) set_mp_short (one, (MP_T) 1, 0, digits_g);
2817 (void) mul_mp (p, z_g, x_g, x_g, digits_g);
2818 (void) sub_mp (p, z_g, one, z_g, digits_g);
2819 if (sqrt_mp (p, z_g, z_g, digits) == NO_MP) {
2820 errno = EDOM;
2821 stack_pointer = pop_sp;
2822 return (NO_MP);
2823 }
2824 if (MP_DIGIT (z_g, 1) == 0) {
2825 (void) mp_pi (p, z, MP_HALF_PI, digits);
2826 MP_DIGIT (z, 1) = (MP_DIGIT (x_g, 1) >= 0 ? MP_DIGIT (z, 1) : -MP_DIGIT (z, 1));
2827 stack_pointer = pop_sp;
2828 return (z);
2829 }
2830 if (div_mp (p, x_g, x_g, z_g, digits_g) == NO_MP) {
2831 errno = EDOM;
2832 stack_pointer = pop_sp;
2833 return (NO_MP);
2834 }
2835 (void) shorten_mp (p, y, digits, x_g, digits_g);
2836 (void) atan_mp (p, z, y, digits);
2837 stack_pointer = pop_sp;
2838 return (z);
2839 }
2840
2841 /**
2842 @brief Set "z" to arccos ("x").
2843 @param p Node in syntax tree.
2844 @param z Multiprecision number.
2845 @param x Multiprecision number.
2846 @param digits Precision in mp-digits.
2847 @return Result "z".
2848 **/
2849
2850 MP_T *
acos_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2851 acos_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2852 {
2853 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2854 MP_T *one, *x_g, *y, *z_g;
2855 BOOL_T negative = (BOOL_T) (MP_DIGIT (x, 1) < 0);
2856 if (MP_DIGIT (x, 1) == 0) {
2857 (void) mp_pi (p, z, MP_HALF_PI, digits);
2858 stack_pointer = pop_sp;
2859 return (z);
2860 }
2861 STACK_MP (y, p, digits);
2862 STACK_MP (x_g, p, digits_g);
2863 STACK_MP (z_g, p, digits_g);
2864 STACK_MP (one, p, digits_g);
2865 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2866 (void) set_mp_short (one, (MP_T) 1, 0, digits_g);
2867 (void) mul_mp (p, z_g, x_g, x_g, digits_g);
2868 (void) sub_mp (p, z_g, one, z_g, digits_g);
2869 if (sqrt_mp (p, z_g, z_g, digits) == NO_MP) {
2870 errno = EDOM;
2871 stack_pointer = pop_sp;
2872 return (NO_MP);
2873 }
2874 if (div_mp (p, x_g, z_g, x_g, digits_g) == NO_MP) {
2875 errno = EDOM;
2876 stack_pointer = pop_sp;
2877 return (NO_MP);
2878 }
2879 (void) shorten_mp (p, y, digits, x_g, digits_g);
2880 (void) atan_mp (p, z, y, digits);
2881 if (negative) {
2882 (void) mp_pi (p, y, MP_PI, digits);
2883 (void) add_mp (p, z, z, y, digits);
2884 }
2885 stack_pointer = pop_sp;
2886 return (z);
2887 }
2888
2889 /**
2890 @brief Set "z" to arctan ("x").
2891 @param p Node in syntax tree.
2892 @param z Multiprecision number.
2893 @param x Multiprecision number.
2894 @param digits Precision in mp-digits.
2895 @return Result "z".
2896 **/
2897
2898 MP_T *
atan_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)2899 atan_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
2900 {
2901 /* Depending on the argument we choose either Taylor or Newton */
2902 int pop_sp = stack_pointer, digits_g = FUN_DIGITS (digits);
2903 MP_T *x_g, *z_g;
2904 BOOL_T flip, negative;
2905 STACK_MP (x_g, p, digits_g);
2906 STACK_MP (z_g, p, digits_g);
2907 if (MP_DIGIT (x, 1) == 0) {
2908 stack_pointer = pop_sp;
2909 SET_MP_ZERO (z, digits);
2910 return (z);
2911 }
2912 (void) lengthen_mp (p, x_g, digits_g, x, digits);
2913 negative = (BOOL_T) (MP_DIGIT (x_g, 1) < 0);
2914 if (negative) {
2915 MP_DIGIT (x_g, 1) = -MP_DIGIT (x_g, 1);
2916 }
2917 /* For larger arguments we use atan(x) = pi/2 - atan(1/x) */
2918 flip = (BOOL_T) (((MP_EXPONENT (x_g) > 0) || (MP_EXPONENT (x_g) == 0 && MP_DIGIT (x_g, 1) > 1)) && (MP_DIGIT (x_g, 1) != 0));
2919 if (flip) {
2920 (void) rec_mp (p, x_g, x_g, digits_g);
2921 }
2922 if (MP_EXPONENT (x_g) < -1 || (MP_EXPONENT (x_g) == -1 && MP_DIGIT (x_g, 1) < MP_RADIX / 100)) {
2923 /* Taylor sum for x close to zero.
2924 arctan (x) = x - x ** 3 / 3 + x ** 5 / 5 - x ** 7 / 7 + ..
2925 This is faster for small x and avoids cancellation */
2926 MP_T *tmp, *a68g_pow, *sqr;
2927 int n = 3;
2928 BOOL_T iterate, even;
2929 STACK_MP (tmp, p, digits_g);
2930 STACK_MP (a68g_pow, p, digits_g);
2931 STACK_MP (sqr, p, digits_g);
2932 (void) mul_mp (p, sqr, x_g, x_g, digits_g);
2933 (void) mul_mp (p, a68g_pow, sqr, x_g, digits_g);
2934 MOVE_MP (z_g, x_g, digits_g);
2935 even = A68_FALSE;
2936 iterate = (BOOL_T) (MP_DIGIT (a68g_pow, 1) != 0);
2937 while (iterate) {
2938 (void) div_mp_digit (p, tmp, a68g_pow, (MP_T) n, digits_g);
2939 if (MP_EXPONENT (tmp) <= (MP_EXPONENT (z_g) - digits_g)) {
2940 iterate = A68_FALSE;
2941 } else {
2942 if (even) {
2943 (void) add_mp (p, z_g, z_g, tmp, digits_g);
2944 even = A68_FALSE;
2945 } else {
2946 (void) sub_mp (p, z_g, z_g, tmp, digits_g);
2947 even = A68_TRUE;
2948 }
2949 (void) mul_mp (p, a68g_pow, a68g_pow, sqr, digits_g);
2950 n += 2;
2951 }
2952 }
2953 } else {
2954 /* Newton's method: x<n+1> = x<n> - cos (x<n>) * (sin (x<n>) - a cos (x<n>)) */
2955 MP_T *tmp, *z_0, *sns, *cns, *one;
2956 int decimals, digits_h;
2957 STACK_MP (tmp, p, digits_g);
2958 STACK_MP (z_0, p, digits_g);
2959 STACK_MP (sns, p, digits_g);
2960 STACK_MP (cns, p, digits_g);
2961 STACK_MP (one, p, digits_g);
2962 SET_MP_ZERO (z_0, digits_g);
2963 (void) set_mp_short (one, (MP_T) 1, 0, digits_g);
2964 /* Construct an estimate */
2965 (void) real_to_mp (p, z_g, atan (mp_to_real (p, x_g, digits_g)), digits_g);
2966 decimals = DOUBLE_ACCURACY;
2967 do {
2968 decimals <<= 1;
2969 digits_h = MINIMUM (1 + decimals / LOG_MP_BASE, digits_g);
2970 (void) sin_mp (p, sns, z_g, digits_h);
2971 (void) mul_mp (p, tmp, sns, sns, digits_h);
2972 (void) sub_mp (p, tmp, one, tmp, digits_h);
2973 (void) sqrt_mp (p, cns, tmp, digits_h);
2974 (void) mul_mp (p, tmp, x_g, cns, digits_h);
2975 (void) sub_mp (p, tmp, sns, tmp, digits_h);
2976 (void) mul_mp (p, tmp, tmp, cns, digits_h);
2977 (void) sub_mp (p, z_g, z_g, tmp, digits_h);
2978 } while (decimals < digits_g * LOG_MP_BASE);
2979 }
2980 if (flip) {
2981 MP_T *hpi;
2982 STACK_MP (hpi, p, digits_g);
2983 (void) sub_mp (p, z_g, mp_pi (p, hpi, MP_HALF_PI, digits_g), z_g, digits_g);
2984 }
2985 (void) shorten_mp (p, z, digits, z_g, digits_g);
2986 MP_DIGIT (z, 1) = (negative ? -MP_DIGIT (z, 1) : MP_DIGIT (z, 1));
2987 /* Exit */
2988 stack_pointer = pop_sp;
2989 return (z);
2990 }
2991
2992 /**
2993 @brief Set "z" to atan2 ("x", "y").
2994 @param p Node in syntax tree.
2995 @param z Multiprecision number.
2996 @param x Multiprecision number.
2997 @param y Multiprecision number.
2998 @param digits Precision in mp-digits.
2999 @return Result "z".
3000 **/
3001
3002 MP_T *
atan2_mp(NODE_T * p,MP_T * z,MP_T * x,MP_T * y,int digits)3003 atan2_mp (NODE_T * p, MP_T * z, MP_T * x, MP_T * y, int digits)
3004 {
3005 ADDR_T pop_sp = stack_pointer;
3006 MP_T *t;
3007 STACK_MP (t, p, digits);
3008 if (MP_DIGIT (x, 1) == 0 && MP_DIGIT (y, 1) == 0) {
3009 errno = EDOM;
3010 stack_pointer = pop_sp;
3011 return (NO_MP);
3012 } else {
3013 BOOL_T flip = (BOOL_T) (MP_DIGIT (y, 1) < 0);
3014 MP_DIGIT (y, 1) = ABS (MP_DIGIT (y, 1));
3015 if (IS_ZERO_MP (x)) {
3016 (void) mp_pi (p, z, MP_HALF_PI, digits);
3017 } else {
3018 BOOL_T flop = (BOOL_T) (MP_DIGIT (x, 1) <= 0);
3019 MP_DIGIT (x, 1) = ABS (MP_DIGIT (x, 1));
3020 (void) div_mp (p, z, y, x, digits);
3021 (void) atan_mp (p, z, z, digits);
3022 if (flop) {
3023 (void) mp_pi (p, t, MP_PI, digits);
3024 (void) sub_mp (p, z, t, z, digits);
3025 }
3026 }
3027 if (flip) {
3028 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
3029 }
3030 }
3031 stack_pointer = pop_sp;
3032 return (z);
3033 }
3034
3035 /**
3036 @brief Set "a" I "b" to "a" I "b" * "c" I "d".
3037 @param p Node in syntax tree.
3038 @param a Real mp number.
3039 @param b Imaginary mp number.
3040 @param c Real mp number.
3041 @param d Imaginary mp number.
3042 @param digits Precision in mp-digits.
3043 @return Real part of result.
3044 **/
3045
3046 MP_T *
cmul_mp(NODE_T * p,MP_T * a,MP_T * b,MP_T * c,MP_T * d,int digits)3047 cmul_mp (NODE_T * p, MP_T * a, MP_T * b, MP_T * c, MP_T * d, int digits)
3048 {
3049 ADDR_T pop_sp = stack_pointer;
3050 int digits_g = FUN_DIGITS (digits);
3051 MP_T *la, *lb, *lc, *ld, *ac, *bd, *ad, *bc;
3052 STACK_MP (la, p, digits_g);
3053 STACK_MP (lb, p, digits_g);
3054 STACK_MP (lc, p, digits_g);
3055 STACK_MP (ld, p, digits_g);
3056 (void) lengthen_mp (p, la, digits_g, a, digits);
3057 (void) lengthen_mp (p, lb, digits_g, b, digits);
3058 (void) lengthen_mp (p, lc, digits_g, c, digits);
3059 (void) lengthen_mp (p, ld, digits_g, d, digits);
3060 STACK_MP (ac, p, digits_g);
3061 STACK_MP (bd, p, digits_g);
3062 STACK_MP (ad, p, digits_g);
3063 STACK_MP (bc, p, digits_g);
3064 (void) mul_mp (p, ac, la, lc, digits_g);
3065 (void) mul_mp (p, bd, lb, ld, digits_g);
3066 (void) mul_mp (p, ad, la, ld, digits_g);
3067 (void) mul_mp (p, bc, lb, lc, digits_g);
3068 (void) sub_mp (p, la, ac, bd, digits_g);
3069 (void) add_mp (p, lb, ad, bc, digits_g);
3070 (void) shorten_mp (p, a, digits, la, digits_g);
3071 (void) shorten_mp (p, b, digits, lb, digits_g);
3072 stack_pointer = pop_sp;
3073 return (a);
3074 }
3075
3076 /**
3077 @brief Set "a" I "b" to "a" I "b" / "c" I "d".
3078 @param p Node in syntax tree.
3079 @param a Real mp number.
3080 @param b Imaginary mp number.
3081 @param c Real mp number.
3082 @param d Imaginary mp number.
3083 @param digits Precision in mp-digits.
3084 @return Real part of result.
3085 **/
3086
3087 MP_T *
cdiv_mp(NODE_T * p,MP_T * a,MP_T * b,MP_T * c,MP_T * d,int digits)3088 cdiv_mp (NODE_T * p, MP_T * a, MP_T * b, MP_T * c, MP_T * d, int digits)
3089 {
3090 ADDR_T pop_sp = stack_pointer;
3091 MP_T *q, *r;
3092 if (MP_DIGIT (c, 1) == (MP_T) 0 && MP_DIGIT (d, 1) == (MP_T) 0) {
3093 errno = ERANGE;
3094 return (NO_MP);
3095 }
3096 STACK_MP (q, p, digits);
3097 STACK_MP (r, p, digits);
3098 MOVE_MP (q, c, digits);
3099 MOVE_MP (r, d, digits);
3100 MP_DIGIT (q, 1) = ABS (MP_DIGIT (q, 1));
3101 MP_DIGIT (r, 1) = ABS (MP_DIGIT (r, 1));
3102 (void) sub_mp (p, q, q, r, digits);
3103 if (MP_DIGIT (q, 1) >= 0) {
3104 if (div_mp (p, q, d, c, digits) == NO_MP) {
3105 errno = ERANGE;
3106 return (NO_MP);
3107 }
3108 (void) mul_mp (p, r, d, q, digits);
3109 (void) add_mp (p, r, r, c, digits);
3110 (void) mul_mp (p, c, b, q, digits);
3111 (void) add_mp (p, c, c, a, digits);
3112 (void) div_mp (p, c, c, r, digits);
3113 (void) mul_mp (p, d, a, q, digits);
3114 (void) sub_mp (p, d, b, d, digits);
3115 (void) div_mp (p, d, d, r, digits);
3116 } else {
3117 if (div_mp (p, q, c, d, digits) == NO_MP) {
3118 errno = ERANGE;
3119 return (NO_MP);
3120 }
3121 (void) mul_mp (p, r, c, q, digits);
3122 (void) add_mp (p, r, r, d, digits);
3123 (void) mul_mp (p, c, a, q, digits);
3124 (void) add_mp (p, c, c, b, digits);
3125 (void) div_mp (p, c, c, r, digits);
3126 (void) mul_mp (p, d, b, q, digits);
3127 (void) sub_mp (p, d, d, a, digits);
3128 (void) div_mp (p, d, d, r, digits);
3129 }
3130 MOVE_MP (a, c, digits);
3131 MOVE_MP (b, d, digits);
3132 stack_pointer = pop_sp;
3133 return (a);
3134 }
3135
3136 /**
3137 @brief Set "r" I "i" to sqrt ("r" I "i").
3138 @param p Node in syntax tree.
3139 @param r Multiprecision real part.
3140 @param i Multiprecision imaginary part.
3141 @param digits Precision in mp-digits.
3142 @return Real part of result.
3143 **/
3144
3145 MP_T *
csqrt_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3146 csqrt_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3147 {
3148 ADDR_T pop_sp = stack_pointer;
3149 MP_T *re, *im;
3150 int digits_g = FUN_DIGITS (digits);
3151 STACK_MP (re, p, digits_g);
3152 STACK_MP (im, p, digits_g);
3153 (void) lengthen_mp (p, re, digits_g, r, digits);
3154 (void) lengthen_mp (p, im, digits_g, i, digits);
3155 if (IS_ZERO_MP (re) && IS_ZERO_MP (im)) {
3156 SET_MP_ZERO (re, digits_g);
3157 SET_MP_ZERO (im, digits_g);
3158 } else {
3159 MP_T *c1, *t, *x, *y, *u, *v, *w;
3160 STACK_MP (c1, p, digits_g);
3161 STACK_MP (t, p, digits_g);
3162 STACK_MP (x, p, digits_g);
3163 STACK_MP (y, p, digits_g);
3164 STACK_MP (u, p, digits_g);
3165 STACK_MP (v, p, digits_g);
3166 STACK_MP (w, p, digits_g);
3167 (void) set_mp_short (c1, (MP_T) 1, 0, digits_g);
3168 MOVE_MP (x, re, digits_g);
3169 MOVE_MP (y, im, digits_g);
3170 MP_DIGIT (x, 1) = ABS (MP_DIGIT (x, 1));
3171 MP_DIGIT (y, 1) = ABS (MP_DIGIT (y, 1));
3172 (void) sub_mp (p, w, x, y, digits_g);
3173 if (MP_DIGIT (w, 1) >= 0) {
3174 (void) div_mp (p, t, y, x, digits_g);
3175 (void) mul_mp (p, v, t, t, digits_g);
3176 (void) add_mp (p, u, c1, v, digits_g);
3177 (void) sqrt_mp (p, v, u, digits_g);
3178 (void) add_mp (p, u, c1, v, digits_g);
3179 (void) half_mp (p, v, u, digits_g);
3180 (void) sqrt_mp (p, u, v, digits_g);
3181 (void) sqrt_mp (p, v, x, digits_g);
3182 (void) mul_mp (p, w, u, v, digits_g);
3183 } else {
3184 (void) div_mp (p, t, x, y, digits_g);
3185 (void) mul_mp (p, v, t, t, digits_g);
3186 (void) add_mp (p, u, c1, v, digits_g);
3187 (void) sqrt_mp (p, v, u, digits_g);
3188 (void) add_mp (p, u, t, v, digits_g);
3189 (void) half_mp (p, v, u, digits_g);
3190 (void) sqrt_mp (p, u, v, digits_g);
3191 (void) sqrt_mp (p, v, y, digits_g);
3192 (void) mul_mp (p, w, u, v, digits_g);
3193 }
3194 if (MP_DIGIT (re, 1) >= 0) {
3195 MOVE_MP (re, w, digits_g);
3196 (void) add_mp (p, u, w, w, digits_g);
3197 (void) div_mp (p, im, im, u, digits_g);
3198 } else {
3199 if (MP_DIGIT (im, 1) < 0) {
3200 MP_DIGIT (w, 1) = -MP_DIGIT (w, 1);
3201 }
3202 (void) add_mp (p, v, w, w, digits_g);
3203 (void) div_mp (p, re, im, v, digits_g);
3204 MOVE_MP (im, w, digits_g);
3205 }
3206 }
3207 (void) shorten_mp (p, r, digits, re, digits_g);
3208 (void) shorten_mp (p, i, digits, im, digits_g);
3209 stack_pointer = pop_sp;
3210 return (r);
3211 }
3212
3213 /**
3214 @brief Set "r" I "i" to exp("r" I "i").
3215 @param p Node in syntax tree.
3216 @param r Multiprecision real part.
3217 @param i Multiprecision imaginary part.
3218 @param digits Precision in mp-digits.
3219 @return Real part of result.
3220 **/
3221
3222 MP_T *
cexp_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3223 cexp_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3224 {
3225 ADDR_T pop_sp = stack_pointer;
3226 MP_T *re, *im, *u;
3227 int digits_g = FUN_DIGITS (digits);
3228 STACK_MP (re, p, digits_g);
3229 STACK_MP (im, p, digits_g);
3230 (void) lengthen_mp (p, re, digits_g, r, digits);
3231 (void) lengthen_mp (p, im, digits_g, i, digits);
3232 STACK_MP (u, p, digits_g);
3233 (void) exp_mp (p, u, re, digits_g);
3234 (void) cos_mp (p, re, im, digits_g);
3235 (void) sin_mp (p, im, im, digits_g);
3236 (void) mul_mp (p, re, re, u, digits_g);
3237 (void) mul_mp (p, im, im, u, digits_g);
3238 (void) shorten_mp (p, r, digits, re, digits_g);
3239 (void) shorten_mp (p, i, digits, im, digits_g);
3240 stack_pointer = pop_sp;
3241 return (r);
3242 }
3243
3244 /**
3245 @brief Set "r" I "i" to ln ("r" I "i").
3246 @param p Node in syntax tree.
3247 @param r Multiprecision real part.
3248 @param i Multiprecision imaginary part.
3249 @param digits Precision in mp-digits.
3250 @return Real part of result.
3251 **/
3252
3253 MP_T *
cln_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3254 cln_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3255 {
3256 ADDR_T pop_sp = stack_pointer;
3257 MP_T *re, *im, *u, *v, *s, *t;
3258 int digits_g = FUN_DIGITS (digits);
3259 STACK_MP (re, p, digits_g);
3260 STACK_MP (im, p, digits_g);
3261 (void) lengthen_mp (p, re, digits_g, r, digits);
3262 (void) lengthen_mp (p, im, digits_g, i, digits);
3263 STACK_MP (s, p, digits_g);
3264 STACK_MP (t, p, digits_g);
3265 STACK_MP (u, p, digits_g);
3266 STACK_MP (v, p, digits_g);
3267 MOVE_MP (u, re, digits_g);
3268 MOVE_MP (v, im, digits_g);
3269 (void) hypot_mp (p, s, u, v, digits_g);
3270 MOVE_MP (u, re, digits_g);
3271 MOVE_MP (v, im, digits_g);
3272 (void) atan2_mp (p, t, u, v, digits_g);
3273 (void) ln_mp (p, re, s, digits_g);
3274 MOVE_MP (im, t, digits_g);
3275 (void) shorten_mp (p, r, digits, re, digits_g);
3276 (void) shorten_mp (p, i, digits, im, digits_g);
3277 stack_pointer = pop_sp;
3278 return (r);
3279 }
3280
3281 /**
3282 @brief Set "r" I "i" to sin ("r" I "i").
3283 @param p Node in syntax tree.
3284 @param r Multiprecision real part.
3285 @param i Multiprecision imaginary part.
3286 @param digits Precision in mp-digits.
3287 @return Real part of result.
3288 **/
3289
3290 MP_T *
csin_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3291 csin_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3292 {
3293 ADDR_T pop_sp = stack_pointer;
3294 MP_T *re, *im, *s, *c, *sh, *ch;
3295 int digits_g = FUN_DIGITS (digits);
3296 STACK_MP (re, p, digits_g);
3297 STACK_MP (im, p, digits_g);
3298 (void) lengthen_mp (p, re, digits_g, r, digits);
3299 (void) lengthen_mp (p, im, digits_g, i, digits);
3300 STACK_MP (s, p, digits_g);
3301 STACK_MP (c, p, digits_g);
3302 STACK_MP (sh, p, digits_g);
3303 STACK_MP (ch, p, digits_g);
3304 if (IS_ZERO_MP (im)) {
3305 (void) sin_mp (p, re, re, digits_g);
3306 SET_MP_ZERO (im, digits_g);
3307 } else {
3308 (void) sin_mp (p, s, re, digits_g);
3309 (void) cos_mp (p, c, re, digits_g);
3310 (void) hyp_mp (p, sh, ch, im, digits_g);
3311 (void) mul_mp (p, re, s, ch, digits_g);
3312 (void) mul_mp (p, im, c, sh, digits_g);
3313 }
3314 (void) shorten_mp (p, r, digits, re, digits_g);
3315 (void) shorten_mp (p, i, digits, im, digits_g);
3316 stack_pointer = pop_sp;
3317 return (r);
3318 }
3319
3320 /**
3321 @brief Set "r" I "i" to cos ("r" I "i").
3322 @param p Node in syntax tree.
3323 @param r Multiprecision real part.
3324 @param i Multiprecision imaginary part.
3325 @param digits Precision in mp-digits.
3326 @return Real part of result.
3327 **/
3328
3329 MP_T *
ccos_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3330 ccos_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3331 {
3332 ADDR_T pop_sp = stack_pointer;
3333 MP_T *re, *im, *s, *c, *sh, *ch;
3334 int digits_g = FUN_DIGITS (digits);
3335 STACK_MP (re, p, digits_g);
3336 STACK_MP (im, p, digits_g);
3337 (void) lengthen_mp (p, re, digits_g, r, digits);
3338 (void) lengthen_mp (p, im, digits_g, i, digits);
3339 STACK_MP (s, p, digits_g);
3340 STACK_MP (c, p, digits_g);
3341 STACK_MP (sh, p, digits_g);
3342 STACK_MP (ch, p, digits_g);
3343 if (IS_ZERO_MP (im)) {
3344 (void) cos_mp (p, re, re, digits_g);
3345 SET_MP_ZERO (im, digits_g);
3346 } else {
3347 (void) sin_mp (p, s, re, digits_g);
3348 (void) cos_mp (p, c, re, digits_g);
3349 (void) hyp_mp (p, sh, ch, im, digits_g);
3350 MP_DIGIT (sh, 1) = -MP_DIGIT (sh, 1);
3351 (void) mul_mp (p, re, c, ch, digits_g);
3352 (void) mul_mp (p, im, s, sh, digits_g);
3353 }
3354 (void) shorten_mp (p, r, digits, re, digits_g);
3355 (void) shorten_mp (p, i, digits, im, digits_g);
3356 stack_pointer = pop_sp;
3357 return (r);
3358 }
3359
3360 /**
3361 @brief Set "r" I "i" to tan ("r" I "i").
3362 @param p Node in syntax tree.
3363 @param r Multiprecision real part.
3364 @param i Multiprecision imaginary part.
3365 @param digits Precision in mp-digits.
3366 @return Real part of result.
3367 **/
3368
3369 MP_T *
ctan_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3370 ctan_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3371 {
3372 ADDR_T pop_sp = stack_pointer;
3373 MP_T *s, *t, *u, *v;
3374 RESET_ERRNO;
3375 STACK_MP (s, p, digits);
3376 STACK_MP (t, p, digits);
3377 STACK_MP (u, p, digits);
3378 STACK_MP (v, p, digits);
3379 MOVE_MP (u, r, digits);
3380 MOVE_MP (v, i, digits);
3381 (void) csin_mp (p, u, v, digits);
3382 MOVE_MP (s, u, digits);
3383 MOVE_MP (t, v, digits);
3384 MOVE_MP (u, r, digits);
3385 MOVE_MP (v, i, digits);
3386 (void) ccos_mp (p, u, v, digits);
3387 (void) cdiv_mp (p, s, t, u, v, digits);
3388 MOVE_MP (r, s, digits);
3389 MOVE_MP (i, t, digits);
3390 stack_pointer = pop_sp;
3391 return (r);
3392 }
3393
3394 /**
3395 @brief Set "r" I "i" to asin ("r" I "i").
3396 @param p Node in syntax tree.
3397 @param r Multiprecision real part.
3398 @param i Multiprecision imaginary part.
3399 @param digits Precision in mp-digits.
3400 @return Real part of result.
3401 **/
3402
3403 MP_T *
casin_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3404 casin_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3405 {
3406 ADDR_T pop_sp = stack_pointer;
3407 MP_T *re, *im;
3408 int digits_g = FUN_DIGITS (digits);
3409 STACK_MP (re, p, digits_g);
3410 STACK_MP (im, p, digits_g);
3411 (void) lengthen_mp (p, re, digits_g, r, digits);
3412 (void) lengthen_mp (p, im, digits_g, i, digits);
3413 if (IS_ZERO_MP (im)) {
3414 (void) asin_mp (p, re, re, digits_g);
3415 } else {
3416 MP_T *c1, *u, *v, *a, *b;
3417 STACK_MP (c1, p, digits_g);
3418 (void) set_mp_short (c1, (MP_T) 1, 0, digits_g);
3419 STACK_MP (u, p, digits_g);
3420 STACK_MP (v, p, digits_g);
3421 STACK_MP (a, p, digits_g);
3422 STACK_MP (b, p, digits_g);
3423 /* u=sqrt((r+1)^2+i^2), v=sqrt((r-1)^2+i^2) */
3424 (void) add_mp (p, a, re, c1, digits_g);
3425 (void) sub_mp (p, b, re, c1, digits_g);
3426 (void) hypot_mp (p, u, a, im, digits_g);
3427 (void) hypot_mp (p, v, b, im, digits_g);
3428 /* a=(u+v)/2, b=(u-v)/2 */
3429 (void) add_mp (p, a, u, v, digits_g);
3430 (void) half_mp (p, a, a, digits_g);
3431 (void) sub_mp (p, b, u, v, digits_g);
3432 (void) half_mp (p, b, b, digits_g);
3433 /* r=asin(b), i=ln(a+sqrt(a^2-1)) */
3434 (void) mul_mp (p, u, a, a, digits_g);
3435 (void) sub_mp (p, u, u, c1, digits_g);
3436 (void) sqrt_mp (p, u, u, digits_g);
3437 (void) add_mp (p, u, a, u, digits_g);
3438 (void) ln_mp (p, im, u, digits_g);
3439 (void) asin_mp (p, re, b, digits_g);
3440 }
3441 (void) shorten_mp (p, r, digits, re, digits_g);
3442 (void) shorten_mp (p, i, digits, im, digits_g);
3443 stack_pointer = pop_sp;
3444 return (re);
3445 }
3446
3447 /**
3448 @brief Set "r" I "i" to acos ("r" I "i").
3449 @param p Node in syntax tree.
3450 @param r Multiprecision real part.
3451 @param i Multiprecision imaginary part.
3452 @param digits Precision in mp-digits.
3453 @return Real part of result.
3454 **/
3455
3456 MP_T *
cacos_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3457 cacos_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3458 {
3459 ADDR_T pop_sp = stack_pointer;
3460 MP_T *re, *im;
3461 int digits_g = FUN_DIGITS (digits);
3462 STACK_MP (re, p, digits_g);
3463 STACK_MP (im, p, digits_g);
3464 (void) lengthen_mp (p, re, digits_g, r, digits);
3465 (void) lengthen_mp (p, im, digits_g, i, digits);
3466 if (IS_ZERO_MP (im)) {
3467 (void) acos_mp (p, re, re, digits_g);
3468 } else {
3469 MP_T *c1, *u, *v, *a, *b;
3470 STACK_MP (c1, p, digits_g);
3471 (void) set_mp_short (c1, (MP_T) 1, 0, digits_g);
3472 STACK_MP (u, p, digits_g);
3473 STACK_MP (v, p, digits_g);
3474 STACK_MP (a, p, digits_g);
3475 STACK_MP (b, p, digits_g);
3476 /* u=sqrt((r+1)^2+i^2), v=sqrt((r-1)^2+i^2) */
3477 (void) add_mp (p, a, re, c1, digits_g);
3478 (void) sub_mp (p, b, re, c1, digits_g);
3479 (void) hypot_mp (p, u, a, im, digits_g);
3480 (void) hypot_mp (p, v, b, im, digits_g);
3481 /* a=(u+v)/2, b=(u-v)/2 */
3482 (void) add_mp (p, a, u, v, digits_g);
3483 (void) half_mp (p, a, a, digits_g);
3484 (void) sub_mp (p, b, u, v, digits_g);
3485 (void) half_mp (p, b, b, digits_g);
3486 /* r=acos(b), i=-ln(a+sqrt(a^2-1)) */
3487 (void) mul_mp (p, u, a, a, digits_g);
3488 (void) sub_mp (p, u, u, c1, digits_g);
3489 (void) sqrt_mp (p, u, u, digits_g);
3490 (void) add_mp (p, u, a, u, digits_g);
3491 (void) ln_mp (p, im, u, digits_g);
3492 MP_DIGIT (im, 1) = -MP_DIGIT (im, 1);
3493 (void) acos_mp (p, re, b, digits_g);
3494 }
3495 (void) shorten_mp (p, r, digits, re, digits_g);
3496 (void) shorten_mp (p, i, digits, im, digits_g);
3497 stack_pointer = pop_sp;
3498 return (re);
3499 }
3500
3501 /**
3502 @brief Set "r" I "i" to atan ("r" I "i").
3503 @param p Node in syntax tree.
3504 @param r Multiprecision real part.
3505 @param i Multiprecision imaginary part.
3506 @param digits Precision in mp-digits.
3507 @return Real part of result.
3508 **/
3509
3510 MP_T *
catan_mp(NODE_T * p,MP_T * r,MP_T * i,int digits)3511 catan_mp (NODE_T * p, MP_T * r, MP_T * i, int digits)
3512 {
3513 ADDR_T pop_sp = stack_pointer;
3514 MP_T *re, *im, *u, *v;
3515 int digits_g = FUN_DIGITS (digits);
3516 STACK_MP (re, p, digits_g);
3517 STACK_MP (im, p, digits_g);
3518 (void) lengthen_mp (p, re, digits_g, r, digits);
3519 (void) lengthen_mp (p, im, digits_g, i, digits);
3520 STACK_MP (u, p, digits_g);
3521 STACK_MP (v, p, digits_g);
3522 if (IS_ZERO_MP (im)) {
3523 (void) atan_mp (p, u, re, digits_g);
3524 SET_MP_ZERO (v, digits_g);
3525 } else {
3526 MP_T *c1, *a, *b;
3527 STACK_MP (c1, p, digits_g);
3528 (void) set_mp_short (c1, (MP_T) 1, 0, digits_g);
3529 STACK_MP (a, p, digits_g);
3530 STACK_MP (b, p, digits_g);
3531 /* a=sqrt(r^2+(i+1)^2), b=sqrt(r^2+(i-1)^2) */
3532 (void) add_mp (p, a, im, c1, digits_g);
3533 (void) sub_mp (p, b, im, c1, digits_g);
3534 (void) hypot_mp (p, u, re, a, digits_g);
3535 (void) hypot_mp (p, v, re, b, digits_g);
3536 /* im=ln(a/b)/4 */
3537 (void) div_mp (p, u, u, v, digits_g);
3538 (void) ln_mp (p, u, u, digits_g);
3539 (void) half_mp (p, v, u, digits_g);
3540 /* re=atan(2r/(1-r^2-i^2)) */
3541 (void) mul_mp (p, a, re, re, digits_g);
3542 (void) mul_mp (p, b, im, im, digits_g);
3543 (void) sub_mp (p, u, c1, a, digits_g);
3544 (void) sub_mp (p, b, u, b, digits_g);
3545 (void) add_mp (p, a, re, re, digits_g);
3546 (void) div_mp (p, a, a, b, digits_g);
3547 (void) atan_mp (p, u, a, digits_g);
3548 (void) half_mp (p, u, u, digits_g);
3549 }
3550 (void) shorten_mp (p, r, digits, u, digits_g);
3551 (void) shorten_mp (p, i, digits, v, digits_g);
3552 stack_pointer = pop_sp;
3553 return (re);
3554 }
3555
3556 /**
3557 @brief Comparison of "x" and "y".
3558 @param p Node in syntax tree.
3559 @param z Comparison result.
3560 @param x Multiprecision number.
3561 @param y Multiprecision number.
3562 @param digits Precision in mp-digits.
3563 @return Whether x = y.
3564 **/
3565
3566 void
eq_mp(NODE_T * p,A68_BOOL * z,MP_T * x,MP_T * y,int digits)3567 eq_mp (NODE_T * p, A68_BOOL * z, MP_T * x, MP_T * y, int digits)
3568 {
3569 ADDR_T pop_sp = stack_pointer;
3570 MP_T *v;
3571 STACK_MP (v, p, digits);
3572 (void) sub_mp (p, v, x, y, digits);
3573 STATUS (z) = INIT_MASK;
3574 VALUE (z) = (MP_DIGIT (v, 1) == 0 ? A68_TRUE : A68_FALSE);
3575 stack_pointer = pop_sp;
3576 }
3577
3578 /**
3579 @brief Comparison of "x" and "y".
3580 @param p Node in syntax tree.
3581 @param z Comparison result.
3582 @param x Multiprecision number.
3583 @param y Multiprecision number.
3584 @param digits Precision in mp-digits.
3585 @return Whether x != y.
3586 **/
3587
3588 void
ne_mp(NODE_T * p,A68_BOOL * z,MP_T * x,MP_T * y,int digits)3589 ne_mp (NODE_T * p, A68_BOOL * z, MP_T * x, MP_T * y, int digits)
3590 {
3591 ADDR_T pop_sp = stack_pointer;
3592 MP_T *v;
3593 STACK_MP (v, p, digits);
3594 (void) sub_mp (p, v, x, y, digits);
3595 STATUS (z) = INIT_MASK;
3596 VALUE (z) = (MP_DIGIT (v, 1) != 0 ? A68_TRUE : A68_FALSE);
3597 stack_pointer = pop_sp;
3598 }
3599
3600 /**
3601 @brief Comparison of "x" and "y".
3602 @param p Node in syntax tree.
3603 @param z Comparison result.
3604 @param x Multiprecision number.
3605 @param y Multiprecision number.
3606 @param digits Precision in mp-digits.
3607 @return Whether x < y.
3608 **/
3609
3610 void
lt_mp(NODE_T * p,A68_BOOL * z,MP_T * x,MP_T * y,int digits)3611 lt_mp (NODE_T * p, A68_BOOL * z, MP_T * x, MP_T * y, int digits)
3612 {
3613 ADDR_T pop_sp = stack_pointer;
3614 MP_T *v;
3615 STACK_MP (v, p, digits);
3616 (void) sub_mp (p, v, x, y, digits);
3617 STATUS (z) = INIT_MASK;
3618 VALUE (z) = (MP_DIGIT (v, 1) < 0 ? A68_TRUE : A68_FALSE);
3619 stack_pointer = pop_sp;
3620 }
3621
3622 /**
3623 @brief Comparison of "x" and "y".
3624 @param p Node in syntax tree.
3625 @param z Comparison result.
3626 @param x Multiprecision number.
3627 @param y Multiprecision number.
3628 @param digits Precision in mp-digits.
3629 @return Whether x <= y.
3630 **/
3631
3632 void
le_mp(NODE_T * p,A68_BOOL * z,MP_T * x,MP_T * y,int digits)3633 le_mp (NODE_T * p, A68_BOOL * z, MP_T * x, MP_T * y, int digits)
3634 {
3635 ADDR_T pop_sp = stack_pointer;
3636 MP_T *v;
3637 STACK_MP (v, p, digits);
3638 (void) sub_mp (p, v, x, y, digits);
3639 STATUS (z) = INIT_MASK;
3640 VALUE (z) = (MP_DIGIT (v, 1) <= 0 ? A68_TRUE : A68_FALSE);
3641 stack_pointer = pop_sp;
3642 }
3643
3644 /**
3645 @brief Comparison of "x" and "y".
3646 @param p Node in syntax tree.
3647 @param z Comparison result.
3648 @param x Multiprecision number.
3649 @param y Multiprecision number.
3650 @param digits Precision in mp-digits.
3651 @return Whether x > y.
3652 **/
3653
3654 void
gt_mp(NODE_T * p,A68_BOOL * z,MP_T * x,MP_T * y,int digits)3655 gt_mp (NODE_T * p, A68_BOOL * z, MP_T * x, MP_T * y, int digits)
3656 {
3657 ADDR_T pop_sp = stack_pointer;
3658 MP_T *v;
3659 STACK_MP (v, p, digits);
3660 (void) sub_mp (p, v, x, y, digits);
3661 STATUS (z) = INIT_MASK;
3662 VALUE (z) = (MP_DIGIT (v, 1) > 0 ? A68_TRUE : A68_FALSE);
3663 stack_pointer = pop_sp;
3664 }
3665
3666 /**
3667 @brief Comparison of "x" and "y".
3668 @param p Node in syntax tree.
3669 @param z Comparison result.
3670 @param x Multiprecision number.
3671 @param y Multiprecision number.
3672 @param digits Precision in mp-digits.
3673 @return Whether x >= y.
3674 **/
3675
3676 void
ge_mp(NODE_T * p,A68_BOOL * z,MP_T * x,MP_T * y,int digits)3677 ge_mp (NODE_T * p, A68_BOOL * z, MP_T * x, MP_T * y, int digits)
3678 {
3679 ADDR_T pop_sp = stack_pointer;
3680 MP_T *v;
3681 STACK_MP (v, p, digits);
3682 (void) sub_mp (p, v, x, y, digits);
3683 STATUS (z) = INIT_MASK;
3684 VALUE (z) = (MP_DIGIT (v, 1) >= 0 ? A68_TRUE : A68_FALSE);
3685 stack_pointer = pop_sp;
3686 }
3687
3688 /**
3689 @brief Rounding.
3690 @param p Node in syntax tree.
3691 @param z Multiprecision number.
3692 @param x Multiprecision number.
3693 @param digits Precision in mp-digits.
3694 @return Round (x).
3695 **/
3696
3697 MP_T *
round_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)3698 round_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
3699 {
3700 MP_T *y;
3701 STACK_MP (y, p, digits);
3702 (void) set_mp_short (y, (MP_T) (MP_RADIX / 2), -1, digits);
3703 if (MP_DIGIT (x, 1) >= 0) {
3704 (void) add_mp (p, z, x, y, digits);
3705 (void) trunc_mp (p, z, z, digits);
3706 } else {
3707 (void) sub_mp (p, z, x, y, digits);
3708 (void) trunc_mp (p, z, z, digits);
3709 }
3710 MP_STATUS (z) = (MP_T) INIT_MASK;
3711 return (z);
3712 }
3713
3714 /**
3715 @brief Rounding.
3716 @param p Node in syntax tree.
3717 @param z Multiprecision number.
3718 @param x Multiprecision number.
3719 @param digits Precision in mp-digits.
3720 @return Entier (x).
3721 **/
3722
3723 MP_T *
entier_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)3724 entier_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
3725 {
3726 if (MP_DIGIT (x, 1) >= 0) {
3727 (void) trunc_mp (p, z, x, digits);
3728 } else {
3729 MP_T *y;
3730 STACK_MP (y, p, digits);
3731 MOVE_MP (y, z, digits);
3732 (void) trunc_mp (p, z, x, digits);
3733 (void) sub_mp (p, y, y, z, digits);
3734 if (MP_DIGIT (y, 1) != 0) {
3735 (void) set_mp_short (y, (MP_T) 1, 0, digits);
3736 (void) sub_mp (p, z, z, y, digits);
3737 }
3738 }
3739 MP_STATUS (z) = (MP_T) INIT_MASK;
3740 return (z);
3741 }
3742
3743 /**
3744 @brief Absolute value.
3745 @param p Node in syntax tree.
3746 @param z Multiprecision number.
3747 @param x Multiprecision number.
3748 @param digits Precision in mp-digits.
3749 @return |x|
3750 **/
3751
3752 MP_T *
abs_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)3753 abs_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
3754 {
3755 (void) p;
3756 if (x != z) {
3757 MOVE_MP (z, x, digits);
3758 }
3759 MP_DIGIT (z, 1) = fabs (MP_DIGIT (z, 1));
3760 MP_STATUS (z) = (MP_T) INIT_MASK;
3761 return (z);
3762 }
3763
3764 /**
3765 @brief Change sign.
3766 @param p Node in syntax tree.
3767 @param z Multiprecision number.
3768 @param x Multiprecision number.
3769 @param digits Precision in mp-digits.
3770 @return -x
3771 **/
3772
3773 MP_T *
minus_mp(NODE_T * p,MP_T * z,MP_T * x,int digits)3774 minus_mp (NODE_T * p, MP_T * z, MP_T * x, int digits)
3775 {
3776 (void) p;
3777 if (x != z) {
3778 MOVE_MP (z, x, digits);
3779 }
3780 MP_DIGIT (z, 1) = -MP_DIGIT (z, 1);
3781 MP_STATUS (z) = (MP_T) INIT_MASK;
3782 return (z);
3783 }
3784