aboutsummaryrefslogtreecommitdiffstats
path: root/mpfr.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpfr.c')
-rw-r--r--mpfr.c153
1 files changed, 117 insertions, 36 deletions
diff --git a/mpfr.c b/mpfr.c
index db2eb697..673553df 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -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