summaryrefslogtreecommitdiff
path: root/cmp.c
blob: 265c86e21f1aa486650c367fdc48982e9ad7eb1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* (c) PolKA project at Inria Lorraine

written by Paul Zimmermann, February 1999

    returns 0 iff b = c
            a positive value iff b > c
            a negative value iff b < 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).

*/

#include <stdio.h>
#include "gmp.h"
#include "gmp-impl.h"
#include "longlong.h"
#include "mpfr.h"

int mpfr_cmp ( mpfr_srcptr b, mpfr_srcptr c )
{
   long int s, diff_exp;
   unsigned long bn, cn;
   mp_limb_t *bp, *cp;

   s = SIGN(b) * SIGN(c);
   if (s<0) return(SIGN(b));

   /* now signs are equal */

   diff_exp = EXP(b)-EXP(c);
   s = (SIGN(b)>0) ? 1 : -1;

   if (diff_exp>0) return(s*(1+diff_exp));
   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;
   cn = (PREC(c)-1)/mp_bits_per_limb+1;
   bp = MANT(b); cp = MANT(c);

   while (bn && cn) {
     if (bp[--bn] != cp[--cn])
       return((bp[bn]>cp[cn]) ? s : -s);
   }

   if (bn) { while (bn) if (bp[--bn]) return(s); }
   else if (cn) while (cn) if (cp[--cn]) return(-s);

   return 0;
}

/* returns the number of cancelled bits when one subtracts abs(c) from abs(b). 
   Assumes b>=c, which implies EXP(b)>=EXP(c).
   if b=c, returns prec(b).
*/
int mpfr_cmp2 ( mpfr_srcptr b, mpfr_srcptr c )
{
   long int d, bn, cn, k;
   mp_limb_t *bp, *cp, t, u=0, cc=0;

   if (NOTZERO(c)==0) return 0;
   d = EXP(b)-EXP(c);
   k = 0; /* result can be d or d+1 if d>1, or >= d otherwise */
#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);
   /* subtracts 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; /* cannot be zero since b is normalized */
   }
   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 */
       while (bn>=0 && (cc=bp[bn--])==0) k+=mp_bits_per_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
      of cancelled bits in the upper limbs is k */
   count_leading_zeros(u, cc);
   k += u;
   if (cc != (1<<(mp_bits_per_limb-u-1))) return k;
   /* now cc is an exact power of two */
   cc = mp_bits_per_limb-u;
   while (bn>=0) {
     /* computes limb bn of difference.
	cc is previous borrow: either 0 or 1.
     */
     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 return(k);
       }
       else u = cp[cn--];
       if (t>u) return(k); /* no borrow possible */
       t -= u;
       if (t>1) { /* t=0 when diff=0, t=1 when b=0 and c=~0 */
	 count_leading_zeros(u, t);
	 if (u!=~(mp_limb_t)0) return(k+cc+u); /* borrow = 1 */
	 else cc+=mp_bits_per_limb;
       }
     }
     else {
       d -= mp_bits_per_limb;
     }
   }
   return k;
}