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: Andrew J. Schorr
Subject: Re: [bug-gawk] GAWK 4.1.60 DIV() Remainder Bug
Date: Mon, 4 Aug 2014 15:28:01 -0400
User-agent: Mutt/1.5.23 (2014-03-12)

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]