2 * mpfr.c - routines for arbitrary-precision number support in gawk.
6 * Copyright (C) 2012, 2013 the Free Software Foundation, Inc.
8 * This file is part of GAWK, the GNU implementation of the
9 * AWK Programming Language.
11 * GAWK is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
16 * GAWK is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
30 #if !defined(MPFR_VERSION_MAJOR) || MPFR_VERSION_MAJOR < 3
31 typedef mp_exp_t mpfr_exp_t;
34 extern NODE **fmt_list; /* declared in eval.c */
36 mpz_t mpzval; /* GMP integer type, used as temporary in few places */
39 bool do_ieee_fmt; /* IEEE-754 floating-point emulation */
40 mpfr_rnd_t ROUND_MODE;
42 static mpfr_rnd_t get_rnd_mode(const char rmode);
43 static NODE *mpg_force_number(NODE *n);
44 static NODE *mpg_make_number(double);
45 static NODE *mpg_format_val(const char *format, int index, NODE *s);
46 static int mpg_interpret(INSTRUCTION **cp);
48 static mpfr_exp_t min_exp = MPFR_EMIN_DEFAULT;
49 static mpfr_exp_t max_exp = MPFR_EMAX_DEFAULT;
51 /* temporary MPFR floats used to hold converted GMP integer operands */
52 static mpfr_t _mpf_t1;
53 static mpfr_t _mpf_t2;
56 * PRECISION_MIN is the precision used to initialize _mpf_t1 and _mpf_t2.
57 * 64 bits should be enough for exact conversion of most integers to floats.
60 #define PRECISION_MIN 64
62 /* mf = { _mpf_t1, _mpf_t2 } */
63 static inline mpfr_ptr mpg_tofloat(mpfr_ptr mf, mpz_ptr mz);
65 #define MP_FLOAT(T) is_mpg_integer(T) ? mpg_tofloat(_mpf_##T, (T)->mpg_i) : (T)->mpg_numbr
68 /* init_mpfr --- set up MPFR related variables */
71 init_mpfr(mpfr_prec_t prec, const char *rmode)
73 mpfr_set_default_prec(prec);
74 ROUND_MODE = get_rnd_mode(rmode[0]);
75 mpfr_set_default_rounding_mode(ROUND_MODE);
76 make_number = mpg_make_number;
77 str2number = mpg_force_number;
78 format_val = mpg_format_val;
79 cmp_numbers = mpg_cmp;
85 mpfr_init2(_mpf_t1, PRECISION_MIN);
86 mpfr_init2(_mpf_t2, PRECISION_MIN);
89 register_exec_hook(mpg_interpret, 0);
92 /* mpg_node --- allocate a node to store MPFR float or GMP integer */
95 mpg_node(unsigned int tp)
102 /* Initialize, set precision to the default precision, and value to NaN */
103 mpfr_init(r->mpg_numbr);
106 /* Initialize and set value to 0 */
112 r->flags |= MALLOC|NUMBER|NUMCUR;
118 #endif /* defined MBS_SUPPORT */
123 * mpg_make_number --- make a arbitrary-precision number node
124 * and initialize with a C double
128 mpg_make_number(double x)
133 if ((ival = double_to_int(x)) != x) {
136 tval = mpfr_set_d(r->mpg_numbr, x, ROUND_MODE);
137 IEEE_FMT(r->mpg_numbr, tval);
140 mpz_set_d(r->mpg_i, ival);
145 /* mpg_strtoui --- assign arbitrary-precision integral value from a string */
148 mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
155 * mpz_set_str does not like leading 0x or 0X for hex (or 0 for octal)
156 * with a non-zero base argument.
158 if (base == 16 && len >= 2 && *s == '0' && (s[1] == 'x' || s[1] == 'X')) {
160 } else if (base == 8 && len >= 1 && *s == '0') {
204 ret = mpz_set_str(zi, start, base);
213 /* mpg_maybe_float --- test if a string may contain arbitrary-precision float */
216 mpg_maybe_float(const char *str, int use_locale)
221 #if defined(HAVE_LOCALE_H)
223 * loc.decimal_point may not have been initialized yet,
224 * so double check it before using it.
226 if (use_locale && loc.decimal_point != NULL && loc.decimal_point[0] != '\0')
227 dec_point = loc.decimal_point[0]; /* XXX --- assumes one char */
231 && ( ( (s[0] == 'i' || s[0] == 'I')
232 && (s[1] == 'n' || s[1] == 'N')
233 && (s[2] == 'f' || s[2] == 'F'))
234 || ( (s[0] == 'n' || s[0] == 'N')
235 && (s[1] == 'a' || s[1] == 'A')
236 && (s[2] == 'n' || s[2] == 'N'))))
239 for (; *s != '\0'; s++) {
240 if (*s == dec_point || *s == 'e' || *s == 'E')
248 /* mpg_zero --- initialize with arbitrary-precision integer(GMP) and set value to zero */
253 if (is_mpg_float(n)) {
254 mpfr_clear(n->mpg_numbr);
257 if (! is_mpg_integer(n)) {
258 mpz_init(n->mpg_i); /* this also sets its value to 0 */
261 mpz_set_si(n->mpg_i, 0);
265 /* force_mpnum --- force a value to be a GMP integer or MPFR float */
268 force_mpnum(NODE *n, int do_nondec, int use_locale)
270 char *cp, *cpend, *ptr, *cp1;
280 cpend = n->stptr + n->stlen;
281 while (cp < cpend && isspace((unsigned char) *cp))
283 if (cp == cpend) { /* only spaces */
291 if (*cp == '+' || *cp == '-')
297 base = get_numbase(cp1, use_locale);
299 if (! mpg_maybe_float(cp1, use_locale)) {
302 mpg_strtoui(n->mpg_i, cp1, cpend - cp1, & ptr, base);
304 mpz_neg(n->mpg_i, n->mpg_i);
308 if (is_mpg_integer(n)) {
313 if (! is_mpg_float(n)) {
314 mpfr_init(n->mpg_numbr);
319 tval = mpfr_strtofr(n->mpg_numbr, cp, & ptr, base, ROUND_MODE);
320 IEEE_FMT(n->mpg_numbr, tval);
322 /* trailing space is OK for NUMBER */
323 while (isspace((unsigned char) *ptr))
326 if (errno == 0 && ptr == cpend)
332 /* mpg_force_number --- force a value to be a multiple-precision number */
335 mpg_force_number(NODE *n)
337 unsigned int newflags = 0;
339 if (is_mpg_number(n) && (n->flags & NUMCUR) != 0)
342 if ((n->flags & MAYBE_NUM) != 0) {
343 n->flags &= ~MAYBE_NUM;
347 if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), true)) {
348 n->flags |= newflags;
354 /* mpg_format_val --- format a numeric value based on format */
357 mpg_format_val(const char *format, int index, NODE *s)
362 /* create dummy node for a sole use of format_tree */
366 if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) {
367 /* integral value, use %d */
368 r = format_tree("%d", 2, dummy, 2);
371 r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
373 s->stfmt = (char) index;
377 if ((s->flags & STRCUR) != 0)
380 freenode(r); /* Do not unref(r)! We want to keep s->stptr == r->stpr. */
387 /* mpg_cmp --- compare two numbers */
390 mpg_cmp(const NODE *t1, const NODE *t2)
393 * For the purposes of sorting, NaN is considered greater than
394 * any other value, and all NaN values are considered equivalent and equal.
397 if (is_mpg_float(t1)) {
398 if (is_mpg_float(t2)) {
399 if (mpfr_nan_p(t1->mpg_numbr))
400 return ! mpfr_nan_p(t2->mpg_numbr);
401 if (mpfr_nan_p(t2->mpg_numbr))
403 return mpfr_cmp(t1->mpg_numbr, t2->mpg_numbr);
405 if (mpfr_nan_p(t1->mpg_numbr))
407 return mpfr_cmp_z(t1->mpg_numbr, t2->mpg_i);
408 } else if (is_mpg_float(t2)) {
410 if (mpfr_nan_p(t2->mpg_numbr))
412 ret = mpfr_cmp_z(t2->mpg_numbr, t1->mpg_i);
413 return ret > 0 ? -1 : (ret < 0);
414 } else if (is_mpg_integer(t1)) {
415 return mpz_cmp(t1->mpg_i, t2->mpg_i);
418 /* t1 and t2 are AWKNUMs */
419 return cmp_awknums(t1, t2);
424 * mpg_update_var --- update NR or FNR.
425 * NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long)
429 mpg_update_var(NODE *n)
431 NODE *val = n->var_value;
438 } else if (n == FNR_node) {
444 if (mpz_sgn(nq) == 0) {
445 /* Efficiency hack similar to that for AWKNUM */
446 if (is_mpg_float(val) || mpz_get_si(val->mpg_i) != nr) {
448 val = n->var_value = mpg_integer();
449 mpz_set_si(val->mpg_i, nr);
453 val = n->var_value = mpg_integer();
454 mpz_set_si(val->mpg_i, nr);
455 mpz_addmul_ui(val->mpg_i, nq, LONG_MAX); /* val->mpg_i += nq * LONG_MAX */
460 /* mpg_set_var --- set NR or FNR */
467 NODE *val = n->var_value;
471 else if (n == FNR_node)
476 if (is_mpg_integer(val))
479 /* convert float to integer */
480 mpfr_get_z(mpzval, val->mpg_numbr, MPFR_RNDZ);
483 nr = mpz_fdiv_q_ui(nq, r, LONG_MAX); /* nq (MNR or MFNR) is quotient */
484 return nr; /* remainder (NR or FNR) */
487 /* set_PREC --- update MPFR PRECISION related variables when PREC assigned to */
494 static const struct ieee_fmt {
496 mpfr_prec_t precision;
500 { "half", 11, 16, -23 }, /* binary16 */
501 { "single", 24, 128, -148 }, /* binary32 */
502 { "double", 53, 1024, -1073 }, /* binary64 */
503 { "quad", 113, 16384, -16493 }, /* binary128 */
504 { "oct", 237, 262144, -262377 }, /* binary256, not in the IEEE 754-2008 standard */
507 * For any bitwidth = 32 * k ( k >= 4),
508 * precision = 13 + bitwidth - int(4 * log2(bitwidth))
509 * emax = 1 << bitwidth - precision - 1
510 * emin = 4 - emax - precision
517 val = PREC_node->var_value;
518 if ((val->flags & MAYBE_NUM) != 0)
521 if ((val->flags & (STRING|NUMBER)) == STRING) {
524 /* emulate IEEE-754 binary format */
526 for (i = 0, j = sizeof(ieee_fmts)/sizeof(ieee_fmts[0]); i < j; i++) {
527 if (strcasecmp(ieee_fmts[i].name, val->stptr) == 0)
532 prec = ieee_fmts[i].precision;
535 * We *DO NOT* change the MPFR exponent range using
536 * mpfr_set_{emin, emax} here. See format_ieee() for details.
538 max_exp = ieee_fmts[i].emax;
539 min_exp = ieee_fmts[i].emin;
547 prec = get_number_si(val);
548 if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
550 warning(_("PREC value `%.*s' is invalid"), (int) val->stlen, val->stptr);
557 mpfr_set_default_prec(prec);
561 /* get_rnd_mode --- convert string to MPFR rounding mode */
564 get_rnd_mode(const char rmode)
569 return MPFR_RNDN; /* round to nearest (IEEE-754 roundTiesToEven) */
572 return MPFR_RNDZ; /* round toward zero (IEEE-754 roundTowardZero) */
575 return MPFR_RNDU; /* round toward plus infinity (IEEE-754 roundTowardPositive) */
578 return MPFR_RNDD; /* round toward minus infinity (IEEE-754 roundTowardNegative) */
579 #if defined(MPFR_VERSION_MAJOR) && MPFR_VERSION_MAJOR > 2
582 return MPFR_RNDA; /* round away from zero (IEEE-754 roundTiesToAway) */
591 * set_ROUNDMODE --- update MPFR rounding mode related variables
592 * when ROUNDMODE assigned to
599 mpfr_rnd_t rndm = -1;
601 n = force_string(ROUNDMODE_node->var_value);
603 rndm = get_rnd_mode(n->stptr[0]);
605 mpfr_set_default_rounding_mode(rndm);
608 warning(_("RNDMODE value `%.*s' is invalid"), (int) n->stlen, n->stptr);
613 /* format_ieee --- make sure a number follows IEEE-754 floating-point standard */
616 format_ieee(mpfr_ptr x, int tval)
619 * The MPFR doc says that it's our responsibility to make sure all numbers
620 * including those previously created are in range after we've changed the
621 * exponent range. Most MPFR operations and functions require
622 * the input arguments to have exponents within the current exponent range.
623 * Any argument outside the range results in a MPFR assertion failure
626 * $ gawk -M 'BEGIN { x=1.0e-10000; print x+0; PREC="double"; print x+0}'
628 * init2.c:52: MPFR assertion failed ....
630 * A "naive" approach would be to keep track of the ternary state and
631 * the rounding mode for each number, and make sure it is in the current
632 * exponent range (using mpfr_check_range) before using it in an
633 * operation or function. Instead, we adopt the following strategy.
635 * When gawk starts, the exponent range is the MPFR default
636 * [MPFR_EMIN_DEFAULT, MPFR_EMAX_DEFAULT]. Any number that gawk
637 * creates must have exponent in this range (excluding infinities, NaNs and zeros).
638 * Each MPFR operation or function is performed with this default exponent
641 * When emulating IEEE-754 format, the exponents are *temporarily* changed,
642 * mpfr_check_range is called to make sure the number is in the new range,
643 * and mpfr_subnormalize is used to round following the rules of subnormal
644 * arithmetic. The exponent range is then *restored* to the original value
645 * [MPFR_EMIN_DEFAULT, MPFR_EMAX_DEFAULT].
648 (void) mpfr_set_emin(min_exp);
649 (void) mpfr_set_emax(max_exp);
650 tval = mpfr_check_range(x, tval, ROUND_MODE);
651 tval = mpfr_subnormalize(x, tval, ROUND_MODE);
652 (void) mpfr_set_emin(MPFR_EMIN_DEFAULT);
653 (void) mpfr_set_emax(MPFR_EMAX_DEFAULT);
658 /* do_mpfr_atan2 --- do the atan2 function */
661 do_mpfr_atan2(int nargs)
671 if ((t1->flags & (NUMCUR|NUMBER)) == 0)
672 lintwarn(_("atan2: received non-numeric first argument"));
673 if ((t2->flags & (NUMCUR|NUMBER)) == 0)
674 lintwarn(_("atan2: received non-numeric second argument"));
682 /* See MPFR documentation for handling of special values like +inf as an argument */
683 tval = mpfr_atan2(res->mpg_numbr, p1, p2, ROUND_MODE);
684 IEEE_FMT(res->mpg_numbr, tval);
692 #define SPEC_MATH(X) \
697 if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) \
698 lintwarn(_("%s: received non-numeric argument"), #X); \
702 tval = mpfr_##X(res->mpg_numbr, p1, ROUND_MODE); \
703 IEEE_FMT(res->mpg_numbr, tval); \
708 /* do_mpfr_sin --- do the sin function */
711 do_mpfr_sin(int nargs)
716 /* do_mpfr_cos --- do the cos function */
719 do_mpfr_cos(int nargs)
724 /* do_mpfr_exp --- exponential function */
727 do_mpfr_exp(int nargs)
732 /* do_mpfr_log --- the log function */
735 do_mpfr_log(int nargs)
740 /* do_mpfr_sqrt --- do the sqrt function */
743 do_mpfr_sqrt(int nargs)
748 /* do_mpfr_int --- convert double to int for awk */
751 do_mpfr_int(int nargs)
756 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
757 lintwarn(_("int: received non-numeric argument"));
760 if (is_mpg_integer(tmp)) {
762 mpz_set(r->mpg_i, tmp->mpg_i);
764 if (! mpfr_number_p(tmp->mpg_numbr)) {
770 mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
777 /* do_mpfr_compl --- perform a ~ operation */
780 do_mpfr_compl(int nargs)
786 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
787 lintwarn(_("compl: received non-numeric argument"));
790 if (is_mpg_float(tmp)) {
791 mpfr_ptr p = tmp->mpg_numbr;
793 if (! mpfr_number_p(p)) {
800 mpg_fmt(_("compl(%Rg): negative value will give strange results"), p)
802 if (! mpfr_integer_p(p))
804 mpg_fmt(_("comp(%Rg): fractional value will be truncated"), p)
808 mpfr_get_z(mpzval, p, MPFR_RNDZ); /* float to integer conversion */
811 /* (tmp->flags & MPZN) != 0 */
814 if (mpz_sgn(zptr) < 0)
816 mpg_fmt(_("cmpl(%Zd): negative values will give strange results"), zptr)
822 mpz_com(r->mpg_i, zptr);
827 /* get_intval --- get the (converted) integral operand of a binary function. */
830 get_intval(NODE *t1, int argnum, const char *op)
834 if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)
835 lintwarn(_("%s: received non-numeric argument #%d"), op, argnum);
837 (void) force_number(t1);
839 if (is_mpg_float(t1)) {
840 mpfr_ptr left = t1->mpg_numbr;
841 if (! mpfr_number_p(left)) {
845 mpg_fmt(_("%s: argument #%d has invalid value %Rg, using 0"),
849 emalloc(pz, mpz_ptr, sizeof (mpz_t), "get_intval");
851 return pz; /* should be freed */
855 if (mpfr_sgn(left) < 0)
857 mpg_fmt(_("%s: argument #%d negative value %Rg will give strange results"),
861 if (! mpfr_integer_p(left))
863 mpg_fmt(_("%s: argument #%d fractional value %Rg will be truncated"),
868 emalloc(pz, mpz_ptr, sizeof (mpz_t), "get_intval");
870 mpfr_get_z(pz, left, MPFR_RNDZ); /* float to integer conversion */
871 return pz; /* should be freed */
873 /* (t1->flags & MPZN) != 0 */
878 mpg_fmt(_("%s: argument #%d negative value %Zd will give strange results"),
882 return pz; /* must not be freed */
886 /* free_intval --- free the converted integer value returned by get_intval() */
889 free_intval(NODE *t, mpz_ptr pz)
891 if ((t->flags & MPZN) == 0) {
898 /* do_mpfr_lshift --- perform a << operation */
901 do_mpfr_lshift(int nargs)
910 pz1 = get_intval(t1, 1, "lshift");
911 pz2 = get_intval(t2, 2, "lshift");
914 * mpz_get_ui: If op is too big to fit an unsigned long then just
915 * the least significant bits that do fit are returned.
916 * The sign of op is ignored, only the absolute value is used.
919 shift = mpz_get_ui(pz2); /* GMP integer => unsigned long conversion */
921 mpz_mul_2exp(res->mpg_i, pz1, shift); /* res = pz1 * 2^shift */
923 free_intval(t1, pz1);
924 free_intval(t2, pz2);
930 /* do_mpfr_rshift --- perform a >> operation */
933 do_mpfr_rshift(int nargs)
942 pz1 = get_intval(t1, 1, "rshift");
943 pz2 = get_intval(t2, 2, "rshift");
945 /* N.B: See do_mpfp_lshift. */
946 shift = mpz_get_ui(pz2); /* GMP integer => unsigned long conversion */
948 mpz_fdiv_q_2exp(res->mpg_i, pz1, shift); /* res = pz1 / 2^shift, round towards −inf */
950 free_intval(t1, pz1);
951 free_intval(t2, pz2);
958 /* do_mpfr_and --- perform an & operation */
961 do_mpfr_and(int nargs)
968 fatal(_("and: called with less than two arguments"));
971 pz2 = get_intval(t2, nargs, "and");
974 for (i = 1; i < nargs; i++) {
976 pz1 = get_intval(t1, nargs - i, "and");
977 mpz_and(res->mpg_i, pz1, pz2);
978 free_intval(t1, pz1);
981 free_intval(t2, pz2);
990 /* do_mpfr_or --- perform an | operation */
993 do_mpfr_or(int nargs)
1000 fatal(_("or: called with less than two arguments"));
1003 pz2 = get_intval(t2, nargs, "or");
1005 res = mpg_integer();
1006 for (i = 1; i < nargs; i++) {
1008 pz1 = get_intval(t1, nargs - i, "or");
1009 mpz_ior(res->mpg_i, pz1, pz2);
1010 free_intval(t1, pz1);
1013 free_intval(t2, pz2);
1021 /* do_mpfr_xor --- perform an ^ operation */
1024 do_mpfr_xor(int nargs)
1026 NODE *t1, *t2, *res;
1031 fatal(_("xor: called with less than two arguments"));
1034 pz2 = get_intval(t2, nargs, "xor");
1036 res = mpg_integer();
1037 for (i = 1; i < nargs; i++) {
1039 pz1 = get_intval(t1, nargs - i, "xor");
1040 mpz_xor(res->mpg_i, pz1, pz2);
1041 free_intval(t1, pz1);
1044 free_intval(t2, pz2);
1052 /* do_mpfr_strtonum --- the strtonum function */
1055 do_mpfr_strtonum(int nargs)
1060 if ((tmp->flags & (NUMBER|NUMCUR)) == 0) {
1061 r = mpg_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */
1062 r->stptr = tmp->stptr;
1063 r->stlen = tmp->stlen;
1064 force_mpnum(r, true, use_lc_numeric);
1068 (void) force_number(tmp);
1069 if (is_mpg_float(tmp)) {
1072 tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE);
1073 IEEE_FMT(r->mpg_numbr, tval);
1076 mpz_set(r->mpg_i, tmp->mpg_i);
1085 static bool firstrand = true;
1086 static gmp_randstate_t state;
1087 static mpz_t seed; /* current seed */
1089 /* do_mpfr_rand --- do the rand function */
1092 do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
1099 /* Choose the default algorithm */
1100 gmp_randinit_default(state);
1103 * Choose a specific (Mersenne Twister) algorithm in case the default
1104 * changes in the future.
1107 gmp_randinit_mt(state);
1110 mpz_set_ui(seed, 1);
1112 gmp_randseed(state, seed);
1116 tval = mpfr_urandomb(res->mpg_numbr, state);
1117 IEEE_FMT(res->mpg_numbr, tval);
1122 /* do_mpfr_srand --- seed the random number generator */
1125 do_mpfr_srand(int nargs)
1131 /* Choose the default algorithm */
1132 gmp_randinit_default(state);
1135 * Choose a specific algorithm (Mersenne Twister) in case default
1136 * changes in the future.
1139 gmp_randinit_mt(state);
1142 mpz_set_ui(seed, 1);
1143 /* No need to seed state, will change it below */
1147 res = mpg_integer();
1148 mpz_set(res->mpg_i, seed); /* previous seed */
1151 mpz_set_ui(seed, (unsigned long) time((time_t *) 0));
1155 if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
1156 lintwarn(_("srand: received non-numeric argument"));
1158 if (is_mpg_float(tmp))
1159 mpfr_get_z(seed, tmp->mpg_numbr, MPFR_RNDZ);
1160 else /* MP integer */
1161 mpz_set(seed, tmp->mpg_i);
1165 gmp_randseed(state, seed);
1170 * mpg_tofloat --- convert an arbitrary-precision integer operand to
1171 * a float without loss of precision. It is assumed that the
1172 * MPFR variable has already been initialized.
1175 static inline mpfr_ptr
1176 mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
1181 * When implicitely converting a GMP integer operand to a MPFR float, use
1182 * a precision sufficiently large to hold the converted value exactly.
1184 * $ ./gawk -M 'BEGIN { print 13 % 2 }'
1186 * If the user-specified precision is used to convert the integer 13 to a
1187 * float, one will get:
1188 * $ ./gawk -M 'BEGIN { PREC=2; print 13 % 2.0 }'
1192 prec = mpz_sizeinbase(mz, 2); /* most significant 1 bit position starting at 1 */
1193 if (prec > PRECISION_MIN) {
1194 prec -= (size_t) mpz_scan1(mz, 0); /* least significant 1 bit index starting at 0 */
1195 if (prec > MPFR_PREC_MAX)
1196 prec = MPFR_PREC_MAX;
1197 if (prec > PRECISION_MIN)
1198 mpfr_set_prec(mf, prec);
1201 mpfr_set_z(mf, mz, ROUND_MODE);
1206 /* mpg_add --- add arbitrary-precision numbers */
1209 mpg_add(NODE *t1, NODE *t2)
1214 if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
1216 mpz_add(r->mpg_i, t1->mpg_i, t2->mpg_i);
1219 if (is_mpg_integer(t2))
1220 tval = mpfr_add_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
1221 else if (is_mpg_integer(t1))
1222 tval = mpfr_add_z(r->mpg_numbr, t2->mpg_numbr, t1->mpg_i, ROUND_MODE);
1224 tval = mpfr_add(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE);
1225 IEEE_FMT(r->mpg_numbr, tval);
1230 /* mpg_sub --- subtract arbitrary-precision numbers */
1233 mpg_sub(NODE *t1, NODE *t2)
1238 if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
1240 mpz_sub(r->mpg_i, t1->mpg_i, t2->mpg_i);
1243 if (is_mpg_integer(t2))
1244 tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
1245 else if (is_mpg_integer(t1)) {
1246 #if (!defined(MPFR_VERSION) || (MPFR_VERSION < MPFR_VERSION_NUM(3,1,0)))
1250 tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
1251 tval = mpfr_neg(r->mpg_numbr, r->mpg_numbr, ROUND_MODE);
1255 tval = mpfr_z_sub(r->mpg_numbr, t1->mpg_i, t2->mpg_numbr, ROUND_MODE);
1258 tval = mpfr_sub(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE);
1259 IEEE_FMT(r->mpg_numbr, tval);
1264 /* mpg_mul --- multiply arbitrary-precision numbers */
1267 mpg_mul(NODE *t1, NODE *t2)
1272 if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
1274 mpz_mul(r->mpg_i, t1->mpg_i, t2->mpg_i);
1277 if (is_mpg_integer(t2))
1278 tval = mpfr_mul_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
1279 else if (is_mpg_integer(t1))
1280 tval = mpfr_mul_z(r->mpg_numbr, t2->mpg_numbr, t1->mpg_i, ROUND_MODE);
1282 tval = mpfr_mul(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE);
1283 IEEE_FMT(r->mpg_numbr, tval);
1289 /* mpg_pow --- exponentiation involving arbitrary-precision numbers */
1292 mpg_pow(NODE *t1, NODE *t2)
1297 if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
1298 if (mpz_sgn(t2->mpg_i) >= 0 && mpz_fits_ulong_p(t2->mpg_i)) {
1300 mpz_pow_ui(r->mpg_i, t1->mpg_i, mpz_get_ui(t2->mpg_i));
1306 tval = mpfr_pow(r->mpg_numbr, p1, p2, ROUND_MODE);
1307 IEEE_FMT(r->mpg_numbr, tval);
1311 if (is_mpg_integer(t2))
1312 tval = mpfr_pow_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE);
1316 tval = mpfr_pow(r->mpg_numbr, p1, t2->mpg_numbr, ROUND_MODE);
1318 IEEE_FMT(r->mpg_numbr, tval);
1323 /* mpg_div --- arbitrary-precision division */
1326 mpg_div(NODE *t1, NODE *t2)
1331 if (is_mpg_integer(t1) && is_mpg_integer(t2)
1332 && (mpz_sgn(t2->mpg_i) != 0) /* not dividing by 0 */
1333 && mpz_divisible_p(t1->mpg_i, t2->mpg_i)
1336 mpz_divexact(r->mpg_i, t1->mpg_i, t2->mpg_i);
1342 tval = mpfr_div(r->mpg_numbr, p1, p2, ROUND_MODE);
1343 IEEE_FMT(r->mpg_numbr, tval);
1348 /* mpg_mod --- modulus operation with arbitrary-precision numbers */
1351 mpg_mod(NODE *t1, NODE *t2)
1356 if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
1358 mpz_mod(r->mpg_i, t1->mpg_i, t2->mpg_i);
1364 tval = mpfr_fmod(r->mpg_numbr, p1, p2, ROUND_MODE);
1365 IEEE_FMT(r->mpg_numbr, tval);
1371 * mpg_interpret --- pre-exec hook in the interpreter. Handles
1372 * arithmetic operations with MPFR/GMP numbers.
1376 mpg_interpret(INSTRUCTION **cp)
1378 INSTRUCTION *pc = *cp; /* current instruction */
1379 OPCODE op; /* current opcode */
1383 int tval; /* the ternary value returned by a MPFR function */
1385 switch ((op = pc->opcode)) {
1387 t2 = force_number(pc->memory);
1393 r = mpg_add(t1, t2);
1401 t2 = force_number(pc->memory);
1407 r = mpg_sub(t1, t2);
1415 t2 = force_number(pc->memory);
1421 r = mpg_mul(t1, t2);
1429 t2 = force_number(pc->memory);
1435 r = mpg_pow(t1, t2);
1443 t2 = force_number(pc->memory);
1449 r = mpg_div(t1, t2);
1451 if (op == Op_quotient)
1457 t2 = force_number(pc->memory);
1463 r = mpg_mod(t1, t2);
1470 case Op_preincrement:
1471 case Op_predecrement:
1472 lhs = TOP_ADDRESS();
1476 if (is_mpg_integer(t1)) {
1477 if (t1->valref == 1 && t1->flags == (MALLOC|MPZN|NUMCUR|NUMBER))
1478 /* Efficiency hack. Big speed-up (> 30%) in a tight loop */
1481 r = *lhs = mpg_integer();
1482 if (op == Op_preincrement)
1483 mpz_add_ui(r->mpg_i, t1->mpg_i, 1);
1485 mpz_sub_ui(r->mpg_i, t1->mpg_i, 1);
1489 * An optimization like the one above is not going to work
1490 * for a floating-point number. With it,
1491 * gawk -M 'BEGIN { PREC=53; i=2^53+0.0; PREC=113; ++i; print i}'
1492 * will output 2^53 instead of 2^53+1.
1495 r = *lhs = mpg_float();
1496 tval = mpfr_add_si(r->mpg_numbr, t1->mpg_numbr,
1497 op == Op_preincrement ? 1 : -1,
1499 IEEE_FMT(r->mpg_numbr, tval);
1507 case Op_postincrement:
1508 case Op_postdecrement:
1509 lhs = TOP_ADDRESS();
1513 if (is_mpg_integer(t1)) {
1515 mpz_set(r->mpg_i, t1->mpg_i);
1516 if (t1->valref == 1 && t1->flags == (MALLOC|MPZN|NUMCUR|NUMBER))
1517 /* Efficiency hack. Big speed-up (> 30%) in a tight loop */
1520 t2 = *lhs = mpg_integer();
1521 if (op == Op_postincrement)
1522 mpz_add_ui(t2->mpg_i, t1->mpg_i, 1);
1524 mpz_sub_ui(t2->mpg_i, t1->mpg_i, 1);
1527 tval = mpfr_set(r->mpg_numbr, t1->mpg_numbr, ROUND_MODE);
1528 IEEE_FMT(r->mpg_numbr, tval);
1529 t2 = *lhs = mpg_float();
1530 tval = mpfr_add_si(t2->mpg_numbr, t1->mpg_numbr,
1531 op == Op_postincrement ? 1 : -1,
1533 IEEE_FMT(t2->mpg_numbr, tval);
1540 case Op_unary_minus:
1542 if (is_mpg_float(t1)) {
1544 tval = mpfr_neg(r->mpg_numbr, t1->mpg_numbr, ROUND_MODE);
1545 IEEE_FMT(r->mpg_numbr, tval);
1548 mpz_neg(r->mpg_i, t1->mpg_i);
1554 case Op_assign_plus:
1555 case Op_assign_minus:
1556 case Op_assign_times:
1557 case Op_assign_quotient:
1560 lhs = POP_ADDRESS();
1566 case Op_assign_plus:
1567 r = mpg_add(t1, t2);
1569 case Op_assign_minus:
1570 r = mpg_sub(t1, t2);
1572 case Op_assign_times:
1573 r = mpg_mul(t1, t2);
1575 case Op_assign_quotient:
1576 r = mpg_div(t1, t2);
1579 r = mpg_mod(t1, t2);
1582 r = mpg_pow(t1, t2);
1596 return true; /* unhandled */
1599 *cp = pc->nexti; /* next instruction to execute */
1604 /* mpg_fmt --- output formatted string with special MPFR/GMP conversion specifiers */
1607 mpg_fmt(const char *mesg, ...)
1609 static char *tmp = NULL;
1617 va_start(args, mesg);
1618 ret = mpfr_vasprintf(& tmp, mesg, args);
1620 if (ret >= 0 && tmp != NULL)
1625 /* mpfr_unset --- clear out the MPFR values */
1630 if (is_mpg_float(n))
1631 mpfr_clear(n->mpg_numbr);
1632 else if (is_mpg_integer(n))
1633 mpz_clear(n->mpg_i);
1641 /* dummy function */
1647 /* dummy function */
1653 /* dummy function */