bug-gawk
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]