[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [bug-gawk] GAWK 4.1.60 DIV() Remainder Bug
From: |
Aharon Robbins |
Subject: |
Re: [bug-gawk] GAWK 4.1.60 DIV() Remainder Bug |
Date: |
Tue, 05 Aug 2014 16:25:23 +0300 |
User-agent: |
Heirloom mailx 12.5 6/20/10 |
Hi Andy & Katie.
Some quick experimentation convinced me that MPFR was getting this wrong
also. Andy, your analysis down to mpz_mod is great and has saved me some
time. Now we have to figure out WHY mpz_mod isn't doing what it is
supposed to be doing.
In the worst case, I'll just switch out to use the div_mod function that
div() uses, but I'd like to try for a bit to understand why mpz_mod
isn't working.
Thanks!
Arnold
> Date: Mon, 4 Aug 2014 15:28:01 -0400
> From: "Andrew J. Schorr" <address@hidden>
> To: Katherine Wasserman <address@hidden>
> Cc: address@hidden
> Subject: Re: [bug-gawk] GAWK 4.1.60 DIV() Remainder Bug
>
> Hi Katie,
>
> Thanks for the bug report.
>
> On Sun, Aug 03, 2014 at 05:53:05PM -0400, Katherine Wasserman wrote:
> > In version 4.1.60 of GAWK the div() function returns remainders that seem
> > wrong, or at least inconsistent with the standard mod (%) function.
> > This only happens with negative numerators. Programming languages vary on
> > the
> > proper way to deal with this, so I'm not going to suggest that one
> > calculation
> > or the other is correct. However the behavior for bignums and regular
> > integers
> > should at least be the same.
>
> I don't think that's the proper distinction; I believe that whether or not
> "bignums" are used is controlled by the use of the -M switch, not the choice
> of
> '%' vs 'div'. When -M is used, the logic in mpfr.c:mpg_interpret seems
> to override the regular interpret in interpret.h.
>
> But in any case, there is certainly a problem here. For example, using
> the current git master version of gawk:
>
> bash-4.2$ echo -15 7 | ./gawk '{div($1, $2, r); print ($1 % $2),
> r["remainder"]; }'
> -1 -1
> bash-4.2$ echo -15 7 | ./gawk -M '{div($1, $2, r); print ($1 % $2),
> r["remainder"]; }'
> 6 -1
>
> And:
>
> bash-4.2$ echo -15 -7 | ./gawk '{div($1, $2, r); print ($1 % $2),
> r["remainder"]; }'
> -1 -1
> bash-4.2$ echo -15 -7 | ./gawk -M '{div($1, $2, r); print ($1 % $2),
> r["remainder"]; }'
> 6 -1
>
> So the MPFR operators clearly don't work the same way. They should
> be consistent.
>
> The regular (non-bignum) code implements '%' using fmod. I hope that
> is correct POSIX awk behavior.
>
> And fmod(x, y) should behave as follows:
>
> These functions shall return the value x- i* y, for some integer i such
> that, if y is non-zero, the result has the same sign as x and magnitude
> less
> than the magnitude of y.
>
> So the -M result is wrong if we accept fmod as the correct behavior. The
> proper answer is -1 above, since it must have the same sign as x.
>
> The mpfr version is using the mpfr.c:mpg_mod function instead of fmod,
> and that calls out to mpz_mod for integers and mpfr_fmod for floats.
>
> And we can see that floats behave differently (correctly):
>
> bash-4.2$ echo -15.0 7.0 | ./gawk -M '{div($1, $2, r); print ($1 % $2),
> r["remainder"]; }'
> -1 -1
> bash-4.2$ echo -15.0 -7.0 | ./gawk -M '{div($1, $2, r); print ($1 % $2),
> r["remainder"]; }'
> -1 -1
>
> So the problem must be with the use of mpz_mod (which I confirmed in the
> debugger).
>
> Function: void mpz_mod (MP_INT *remainder, MP_INT *divdend, MP_INT *divisor)
>
> Function: void mpz_mod_ui (MP_INT *remainder, MP_INT *divdend, unsigned long
> int divisor)
>
> Divide dividend and divisor and put the remainder in remainder. The
> remainder has the same sign as the dividend, and its absolute value is less
> than the absolute value of the divisor.
>
> I must be having a reading comprehension problem, since this sounds
> the same as the fmod behavior to me. What am I missing?
>
> static NODE *
> mpg_mod(NODE *t1, NODE *t2)
> {
> NODE *r;
> int tval;
>
> if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
> r = mpg_integer();
> mpz_mod(r->mpg_i, t1->mpg_i, t2->mpg_i);
> } else {
> mpfr_ptr p1, p2;
> p1 = MP_FLOAT(t1);
> p2 = MP_FLOAT(t2);
> r = mpg_float();
> tval = mpfr_fmod(r->mpg_numbr, p1, p2, ROUND_MODE);
> IEEE_FMT(r->mpg_numbr, tval);
> }
> return r;
> }
>
> Regards,
> Andy