Checking if A - B > D
Niels Möller
nisse at lysator.liu.se
Sat Sep 13 22:39:15 CEST 2003
nisse at lysator.liu.se (Niels Möller) writes:
> When evaluating Jebelean's criterion for matching partial quotient
> sequences (this is in the context of gcd computation), I need to check if
>
> A - B < D
>
> where A > B.
>
> What's the best way to do this, using mpn functions? A and B are often
> much larger than D, and I'd prefer not using temporaries larger than
> D. In particular, I'd prefer not having to actually compute the
> complete difference A - B.
I ended up with the following function. It's a little too hairy for my
taste, so I wonder if there are any good ways to simplify it.
Regards,
/Niels
/* Checks if a - b < c. Overwrites c. */
int
nhgcd_diff_smaller_p(mp_srcptr ap, mp_size_t asize,
mp_srcptr bp, mp_size_t bsize,
mp_ptr cp, mp_size_t csize)
{
mp_limb_t ch;
mp_limb_t dh;
unsigned i;
#if 1
trace("nhgcd_diff_smaller_p: asize = %d, bsize = %d, csize = %d\n",
asize, bsize, csize);
trace(" a = %Nd\n", ap, asize);
trace(" b = %Nd\n", bp, csize);
trace(" c = %Nd\n", cp, csize);
#endif
ASSERT(MPN_LEQ_P(bp, bsize, ap, asize));
if (csize == 0)
return 0;
if (asize < csize)
return 1;
if (asize > bsize)
{
/* #(a - b) >= asize - 1 */
if (asize > csize + 1)
return 0;
else
{
ASSERT(bsize <= csize);
ch = mpn_add(cp, cp, csize, bp, bsize);
if (ch)
{
if (asize == csize)
return 0;
ASSERT(asize == csize + 1);
if (ap[asize - 1] < ch)
return 1;
else if (ap[asize - 1] > ch)
return 0;
/* The high limb of a is canceled by ch. */
asize--;
}
return MPN_LESS_P(ap, asize, cp, csize);
}
}
/* a and b are of the same size. Equal high limbs cancel out, so
ignore them */
while (asize && ap[asize - 1] == bp[asize - 1])
asize--;
if (asize < csize)
return 1;
/* Now asize = bsize >= csize */
if (asize == csize)
{
ch = mpn_add_n(cp, cp, bp, csize);
if (ch)
return 1;
return MPN_LESS_P(ap, csize, cp, csize);
}
/* asize == bsize > csize. */
if (csize == 0)
return 0;
/* Subtract one from c, transforming the check to a - b <= c */
ASSERT_NOCARRY(mpn_sub_1(cp, cp, csize, 1));
MPN_NORMALIZE(cp, csize);
/* Write a = ah W^k + al, b = bh W^k + bl, where c, al, bl < W^k.
Then a - b <= c is equivalent to
(ah - bh) W^k <= c + bl - al
We always have (ah - bh) >= 0, and
-W^k < c + bl - ah < 2 W^k
*/
/* We know that ah - bh >= 1. Do we have ah - bh >= 2? */
dh = ap[asize - 1] - bp[asize - 1];
if (dh >= 2)
return 0;
/* Compute c += bl - al */
ch = mpn_add_n(cp, cp, bp, csize);
if (ch == 0)
/* c + bl < W^k */
return 0;
ch -= mpn_sub_n(cp, cp, ap, csize);
if (ch == 0)
return 0;
/* W^k <= c + bl - al < 2 W^k. Then (ah - bh) W^k is smaller iff ah
= bh + 1, which happens iff ah ends with 0...0, and bh with
f...f. */
for (i = csize; i < asize - 1; i++)
if (ap[i] != 0 || bp[i] != MP_LIMB_T_MAX)
return 0;
return 1;
}
More information about the gmp-devel
mailing list