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