diff options
author | Kevin Ryde <user42@zip.com.au> | 2004-05-14 00:00:13 +0200 |
---|---|---|
committer | Kevin Ryde <user42@zip.com.au> | 2004-05-14 00:00:13 +0200 |
commit | 6cc8b533365d65a8de2b27387ba7d08f6d5566e4 (patch) | |
tree | f40d4d78f3e60fb4f6e7fca701fb14658a6e97c4 /mpf | |
parent | 2c94cbfa3445b231b076e327a85b85e6162b73cd (diff) | |
download | gmp-6cc8b533365d65a8de2b27387ba7d08f6d5566e4.tar.gz |
* mpf/sub.c: When one operand cancels high limbs of the other, strip
high zeros on the balance before truncating to destination precision.
Truncating first loses accuracy and can lead to a result 0 despite
operands being not equal. Reported by John Abbott.
Also, ensure exponent is zero when result is zero, for instance if
operands are exactly equal.
Diffstat (limited to 'mpf')
-rw-r--r-- | mpf/sub.c | 31 |
1 files changed, 18 insertions, 13 deletions
@@ -1,6 +1,6 @@ /* mpf_sub -- Subtract two floats. -Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software +Copyright 1993, 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of the GNU MP Library. @@ -105,26 +105,29 @@ mpf_sub (mpf_ptr r, mpf_srcptr u, mpf_srcptr v) if (usize == 0) { + /* u cancels high limbs of v, result is rest of v */ + negate ^= 1; + cancellation: + /* strip high zeros before truncating to prec */ + while (vsize != 0 && vp[vsize - 1] == 0) + { + vsize--; + exp--; + } if (vsize > prec) { vp += vsize - prec; vsize = prec; } - rsize = vsize; - tp = (mp_ptr) vp; - negate ^= 1; - goto normalize; + MPN_COPY_INCR (rp, vp, vsize); + rsize = vsize; + goto done; } if (vsize == 0) { - if (usize > prec) - { - up += usize - prec; - usize = prec; - } - rsize = usize; - tp = (mp_ptr) up; - goto normalize; + vp = up; + vsize = usize; + goto cancellation; } } while (up[usize - 1] == vp[vsize - 1]); @@ -401,6 +404,8 @@ general_case: done: r->_mp_size = negate ? -rsize : rsize; + if (rsize == 0) + exp = 0; r->_mp_exp = exp; TMP_FREE (marker); } |