| version 1.1, 2000/09/09 14:12:19 |
version 1.1.1.2, 2003/08/25 16:06:06 |
|
|
| /* mpfr_cmp -- compare two floating-point numbers |
/* mpfr_cmp -- compare two floating-point numbers |
| |
|
| Copyright (C) 1999 PolKA project, Inria Lorraine and Loria |
Copyright 1999, 2001 Free Software Foundation. |
| |
|
| This file is part of the MPFR Library. |
This file is part of the MPFR Library. |
| |
|
| The MPFR Library is free software; you can redistribute it and/or modify |
The MPFR Library is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Library General Public License as published by |
it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or (at your |
the Free Software Foundation; either version 2.1 of the License, or (at your |
| option) any later version. |
option) any later version. |
| |
|
| The MPFR Library is distributed in the hope that it will be useful, but |
The MPFR Library is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| License for more details. |
License for more details. |
| |
|
| You should have received a copy of the GNU Library General Public License |
You should have received a copy of the GNU Lesser General Public License |
| along with the MPFR Library; see the file COPYING.LIB. If not, write to |
along with the MPFR Library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
| MA 02111-1307, USA. */ |
MA 02111-1307, USA. */ |
| |
|
| #include <stdio.h> |
|
| #include "gmp.h" |
#include "gmp.h" |
| #include "gmp-impl.h" |
#include "gmp-impl.h" |
| #include "longlong.h" |
|
| #include "mpfr.h" |
#include "mpfr.h" |
| |
#include "mpfr-impl.h" |
| |
|
| /* returns 0 iff b = c |
/* returns 0 iff b = sign(s) * c |
| a positive value iff b > c |
a positive value iff b > sign(s) * c |
| a negative value iff b < c |
a negative value iff b < sign(s) * c |
| |
|
| More precisely, in case b and c are of same sign, the absolute value |
|
| of the result is one plus the absolute difference between the exponents |
|
| of b and c, i.e. one plus the number of bits shifts to align b and c |
|
| (this value is useful in mpfr_sub). |
|
| |
|
| */ |
*/ |
| |
|
| /* #define DEBUG */ |
int |
| |
mpfr_cmp3 (mpfr_srcptr b, mpfr_srcptr c, int s) |
| /* compares b and sign(s)*c */ |
|
| int |
|
| #if __STDC__ |
|
| mpfr_cmp3 ( mpfr_srcptr b, mpfr_srcptr c, long int s) |
|
| #else |
|
| mpfr_cmp3(b, c, s) |
|
| mpfr_srcptr b; |
|
| mpfr_srcptr c; |
|
| long int s; |
|
| #endif |
|
| { |
{ |
| long int diff_exp; |
mp_exp_t be, ce; |
| unsigned long bn, cn; |
mp_size_t bn, cn; |
| mp_limb_t *bp, *cp; |
mp_limb_t *bp, *cp; |
| |
|
| if (!NOTZERO(b) && !NOTZERO(c)) { return 0; } |
MPFR_ASSERTN(!MPFR_IS_NAN(b)); |
| s = s*SIGN(b)*SIGN(c); |
MPFR_ASSERTN(!MPFR_IS_NAN(c)); |
| if (s<0) return(SIGN(b)); |
s *= MPFR_SIGN(c); |
| |
|
| /* now signs are equal */ |
if (MPFR_IS_INF(b)) |
| |
return (MPFR_IS_INF(c) && s * MPFR_SIGN(b) > 0) ? 0 : MPFR_SIGN(b); |
| |
|
| diff_exp = EXP(b)-EXP(c); |
if (MPFR_IS_INF(c)) |
| s = (SIGN(b)>0) ? 1 : -1; |
return -s; |
| |
|
| if (diff_exp>0) return(s*(1+diff_exp)); |
/* b and c are real numbers */ |
| else if (diff_exp<0) return(s*(-1+diff_exp)); |
|
| /* both signs and exponents are equal */ |
|
| |
|
| bn = (PREC(b)-1)/mp_bits_per_limb+1; |
if (MPFR_IS_ZERO(b)) |
| cn = (PREC(c)-1)/mp_bits_per_limb+1; |
return MPFR_IS_ZERO(c) ? 0 : -s; |
| bp = MANT(b); cp = MANT(c); |
|
| |
|
| while (bn && cn) { |
if (MPFR_IS_ZERO(c)) |
| if (bp[--bn] != cp[--cn]) |
return MPFR_SIGN(b); |
| return((bp[bn]>cp[cn]) ? s : -s); |
|
| } |
|
| |
|
| if (bn) { while (bn) if (bp[--bn]) return(s); } |
if (s * MPFR_SIGN(b) < 0) |
| else if (cn) while (cn) if (cp[--cn]) return(-s); |
return MPFR_SIGN(b); |
| |
|
| return 0; |
/* now signs are equal */ |
| } |
|
| |
|
| /* returns the number of cancelled bits when one subtracts abs(c) from abs(b). |
be = MPFR_EXP(b); |
| Assumes b>=c, which implies EXP(b)>=EXP(c). |
ce = MPFR_EXP(c); |
| if b=c, returns prec(b). |
if (be > ce) |
| */ |
return s; |
| int |
if (be < ce) |
| #if __STDC__ |
return -s; |
| mpfr_cmp2 ( mpfr_srcptr b, mpfr_srcptr c ) |
|
| #else |
|
| mpfr_cmp2(b, c) |
|
| mpfr_srcptr b; |
|
| mpfr_srcptr c; |
|
| #endif |
|
| { |
|
| long int d, bn, cn, k, z; |
|
| mp_limb_t *bp, *cp, t, u=0, cc=0; |
|
| |
|
| #ifdef DEBUG |
/* both signs and exponents are equal */ |
| printf("b="); mpfr_print_raw(b); putchar('\n'); |
|
| printf("c="); mpfr_print_raw(c); putchar('\n'); |
|
| #endif |
|
| if (NOTZERO(c)==0) return (NOTZERO(b)) ? 0 : PREC(b); |
|
| d = EXP(b)-EXP(c); |
|
| k = 0; /* result can be d or d+1 if d>1, or >= d otherwise */ |
|
| /* k is the number of identical bits in the high part, |
|
| then z is the number of possibly cancelled bits */ |
|
| #ifdef DEBUG |
|
| if (d<0) { printf("assumption EXP(b)<EXP(c) violated\n"); exit(1); } |
|
| #endif |
|
| bn = (PREC(b)-1)/mp_bits_per_limb; |
|
| cn = (PREC(c)-1)/mp_bits_per_limb; |
|
| bp = MANT(b); cp = MANT(c); |
|
| /* subtract c from b from most significant to less significant limbs, |
|
| and first determines first non zero limb difference */ |
|
| if (d) |
|
| { |
|
| cc = bp[bn--]; |
|
| if (d<mp_bits_per_limb) |
|
| cc -= cp[cn]>>d; |
|
| } |
|
| else { /* d=0 */ |
|
| while (bn>=0 && cn>=0 && (cc=(bp[bn--]-cp[cn--]))==0) { |
|
| k+=mp_bits_per_limb; |
|
| } |
|
| |
|
| if (cc==0) { /* either bn<0 or cn<0 */ |
bn = (MPFR_PREC(b)-1)/BITS_PER_MP_LIMB; |
| while (bn>=0 && (cc=bp[bn--])==0) k+=mp_bits_per_limb; |
cn = (MPFR_PREC(c)-1)/BITS_PER_MP_LIMB; |
| } |
|
| /* now bn<0 or cc<>0 */ |
|
| if (cc==0 && bn<0) return(PREC(b)); |
|
| } |
|
| |
|
| /* the first non-zero limb difference is cc, and the number |
bp = MPFR_MANT(b); |
| of cancelled bits in the upper limbs is k */ |
cp = MPFR_MANT(c); |
| |
|
| count_leading_zeros(u, cc); |
for ( ; bn >= 0 && cn >= 0; bn--, cn--) |
| k += u; |
|
| |
|
| if (cc != (1<<(mp_bits_per_limb-u-1))) return k; |
|
| |
|
| /* now cc is an exact power of two */ |
|
| if (cc != 1) |
|
| /* We just need to compare the following limbs */ |
|
| /* until two of them differ. The result is either k or k+1. */ |
|
| { |
{ |
| /* First flush all the unmatched limbs of b ; they all have to |
if (bp[bn] > cp[cn]) |
| be 0 in order for the process to go on */ |
return s; |
| while (bn >= 0) |
if (bp[bn] < cp[cn]) |
| { |
return -s; |
| if (cn < 0) { return k; } |
|
| t = bp[bn--]; |
|
| if (d < mp_bits_per_limb) |
|
| { |
|
| if (d) |
|
| { |
|
| u = cp[cn--] << (mp_bits_per_limb - d); |
|
| if (cn >= 0) u+=(cp[cn]>>d); |
|
| } |
|
| else u = cp[cn--]; |
|
| |
|
| if (t > u || (t == u && cn < 0)) return k; |
|
| if (t < u) return k+1; |
|
| } |
|
| else |
|
| if (t) return k; else d -= mp_bits_per_limb; |
|
| } |
|
| |
|
| /* bn < 0; if some limb of c is nonzero, return k+1, otherwise return k*/ |
|
| |
|
| if (cn>=0 && (cp[cn--] << (mp_bits_per_limb - d))) { return k+1; } |
|
| |
|
| while (cn >= 0) |
|
| if (cp[cn--]) return k+1; |
|
| return k; |
|
| } |
} |
| |
|
| /* cc = 1. Too bad. */ |
for ( ; bn >= 0; bn--) |
| z = 0; /* number of possibly cancelled bits - 1 */ |
if (bp[bn]) |
| /* thus result is either k if low(b) >= low(c) |
return s; |
| or k+z+1 if low(b) < low(c) */ |
|
| if (d > mp_bits_per_limb) { return k; } |
|
| |
|
| while (bn >= 0) |
for ( ; cn >= 0; cn--) |
| { |
if (cp[cn]) |
| if (cn < 0) { return k; } |
return -s; |
| |
|
| if (d) |
return 0; |
| { |
|
| u = cp[cn--] << (mp_bits_per_limb - d); |
|
| if (cn >= 0) u+=(cp[cn]>>d); |
|
| } |
|
| else u = cp[cn--]; |
|
| |
|
| /* bp[bn--] > cp[cn--] : no borrow possible, k unchanged |
|
| bp[bn--] = cp[cn--] : need to consider next limbs |
|
| bp[bn--] < cp[cn--] : borrow |
|
| */ |
|
| if ((cc = bp[bn--]) != u) { |
|
| if (cc>u) return k; |
|
| else { count_leading_zeros(u, cc-u); return k + 1 + z + u; } |
|
| } |
|
| else z += mp_bits_per_limb; |
|
| } |
|
| |
|
| if (cn >= 0) |
|
| count_leading_zeros(cc, ~(cp[cn--] << (mp_bits_per_limb - d))); |
|
| else { cc = 0; } |
|
| |
|
| k += cc; |
|
| if (cc < d) return k; |
|
| |
|
| while (cn >= 0 && !~cp[cn--]) { z += mp_bits_per_limb; } |
|
| if (cn >= 0) { count_leading_zeros(cc, ~cp[cn--]); return (k + z + cc); } |
|
| |
|
| return k; /* We **need** that the nonsignificant limbs of c are set |
|
| to zero there */ |
|
| } |
} |