diff options
Diffstat (limited to 'mpfr.c')
-rw-r--r-- | mpfr.c | 153 |
1 files changed, 117 insertions, 36 deletions
@@ -329,7 +329,7 @@ force_mpnum(NODE *n, int do_nondec, int use_locale) IEEE_FMT(n->mpg_numbr, tval); done: /* trailing space is OK for NUMBER */ - while (isspace((unsigned char) *ptr)) + while (ptr < cpend && isspace((unsigned char) *ptr)) ptr++; *cpend = save; if (errno == 0 && ptr == cpend) @@ -343,20 +343,17 @@ done: static NODE * mpg_force_number(NODE *n) { - unsigned int newflags = 0; - - if (is_mpg_number(n) && (n->flags & NUMCUR) != 0) + if ((n->flags & NUMCUR) != 0) return n; - - if ((n->flags & MAYBE_NUM) != 0) { - n->flags &= ~MAYBE_NUM; - newflags = NUMBER; - } + n->flags |= NUMCUR; if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), true)) { - n->flags |= newflags; - n->flags |= NUMCUR; - } + if ((n->flags & MAYBE_NUM) != 0) { + n->flags &= ~(MAYBE_NUM|STRING); + n->flags |= NUMBER; + } + } else + n->flags &= ~MAYBE_NUM; return n; } @@ -375,7 +372,7 @@ mpg_format_val(const char *format, int index, NODE *s) if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) { /* integral value, use %d */ r = format_tree("%d", 2, dummy, 2); - s->stfmt = -1; + s->stfmt = STFMT_UNUSED; } else { r = format_tree(format, fmt_list[index]->stlen, dummy, 2); assert(r != NULL); @@ -523,11 +520,9 @@ set_PREC() if (! do_mpfr) return; - val = PREC_node->var_value; - if ((val->flags & MAYBE_NUM) != 0) - force_number(val); + val = fixtype(PREC_node->var_value); - if ((val->flags & STRCUR) != 0) { + if ((val->flags & STRING) != 0) { int i, j; /* emulate IEEE-754 binary format */ @@ -677,9 +672,9 @@ do_mpfr_atan2(int nargs) t1 = POP_SCALAR(); if (do_lint) { - if ((t1->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("atan2: received non-numeric first argument")); - if ((t2->flags & (NUMCUR|NUMBER)) == 0) + if ((fixtype(t2)->flags & NUMBER) == 0) lintwarn(_("atan2: received non-numeric second argument")); } force_number(t1); @@ -710,7 +705,7 @@ do_mpfr_func(const char *name, mpfr_prec_t argprec; t1 = POP_SCALAR(); - if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("%s: received non-numeric argument"), name); force_number(t1); @@ -777,7 +772,7 @@ do_mpfr_int(int nargs) NODE *tmp, *r; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("int: received non-numeric argument")); force_number(tmp); @@ -807,7 +802,7 @@ do_mpfr_compl(int nargs) mpz_ptr zptr; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("compl: received non-numeric argument")); force_number(tmp); @@ -855,7 +850,7 @@ get_intval(NODE *t1, int argnum, const char *op) { mpz_ptr pz; - if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(t1)->flags & NUMBER) == 0) lintwarn(_("%s: received non-numeric argument #%d"), op, argnum); (void) force_number(t1); @@ -1080,25 +1075,22 @@ do_mpfr_strtonum(int nargs) { NODE *tmp, *r; - tmp = POP_SCALAR(); - if ((tmp->flags & (NUMBER|NUMCUR)) == 0) { + tmp = fixtype(POP_SCALAR()); + if ((tmp->flags & NUMBER) == 0) { r = mpg_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */ r->stptr = tmp->stptr; r->stlen = tmp->stlen; force_mpnum(r, true, use_lc_numeric); r->stptr = NULL; r->stlen = 0; + } else if (is_mpg_float(tmp)) { + int tval; + r = mpg_float(); + tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); } else { - (void) force_number(tmp); - if (is_mpg_float(tmp)) { - int tval; - r = mpg_float(); - tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE); - IEEE_FMT(r->mpg_numbr, tval); - } else { - r = mpg_integer(); - mpz_set(r->mpg_i, tmp->mpg_i); - } + r = mpg_integer(); + mpz_set(r->mpg_i, tmp->mpg_i); } DEREF(tmp); @@ -1176,7 +1168,7 @@ do_mpfr_srand(int nargs) else { NODE *tmp; tmp = POP_SCALAR(); - if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) + if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0) lintwarn(_("srand: received non-numeric argument")); force_number(tmp); if (is_mpg_float(tmp)) @@ -1190,6 +1182,95 @@ do_mpfr_srand(int nargs) return res; } +/* do_mpfr_intdiv --- do integer division, return quotient and remainder in dest array */ + +/* + * We define the semantics as: + * numerator = int(numerator) + * denominator = int(denonmator) + * quotient = int(numerator / denomator) + * remainder = int(numerator % denomator) + */ + +NODE * +do_mpfr_intdiv(int nargs) +{ + NODE *numerator, *denominator, *result; + NODE *num, *denom; + NODE *quotient, *remainder; + NODE *sub, **lhs; + + result = POP_PARAM(); + if (result->type != Node_var_array) + fatal(_("intdiv: third argument is not an array")); + assoc_clear(result); + + denominator = POP_SCALAR(); + numerator = POP_SCALAR(); + + if (do_lint) { + if ((fixtype(numerator)->flags & NUMBER) == 0) + lintwarn(_("intdiv: received non-numeric first argument")); + if ((fixtype(denominator)->flags & NUMBER) == 0) + lintwarn(_("intdiv: received non-numeric second argument")); + } + + (void) force_number(numerator); + (void) force_number(denominator); + + /* convert numerator and denominator to integer */ + if (is_mpg_integer(numerator)) { + num = mpg_integer(); + mpz_set(num->mpg_i, numerator->mpg_i); + } else { + if (! mpfr_number_p(numerator->mpg_numbr)) { + /* [+-]inf or NaN */ + return numerator; + } + + num = mpg_integer(); + mpfr_get_z(num->mpg_i, numerator->mpg_numbr, MPFR_RNDZ); + } + + if (is_mpg_integer(denominator)) { + denom = mpg_integer(); + mpz_set(denom->mpg_i, denominator->mpg_i); + } else { + if (! mpfr_number_p(denominator->mpg_numbr)) { + /* [+-]inf or NaN */ + return denominator; + } + + denom = mpg_integer(); + mpfr_get_z(denom->mpg_i, denominator->mpg_numbr, MPFR_RNDZ); + } + + if (mpz_sgn(denom->mpg_i) == 0) + fatal(_("intdiv: division by zero attempted")); + + quotient = mpg_integer(); + remainder = mpg_integer(); + + /* do the division */ + mpz_tdiv_qr(quotient->mpg_i, remainder->mpg_i, num->mpg_i, denom->mpg_i); + unref(num); + unref(denom); + unref(numerator); + unref(denominator); + + sub = make_string("quotient", 8); + lhs = assoc_lookup(result, sub); + unref(*lhs); + *lhs = quotient; + + sub = make_string("remainder", 9); + lhs = assoc_lookup(result, sub); + unref(*lhs); + *lhs = remainder; + + return make_number((AWKNUM) 0.0); +} + /* * mpg_tofloat --- convert an arbitrary-precision integer operand to * a float without loss of precision. It is assumed that the |