mpir/mpn/generic/nhgcd2.c
jasonmoxham e554550755 for file in $(find -name \*.c ) ; do sed -e "s/#include \"gmp\.h\"/#include \"mpir.h\"/g" $file > temp ; mv temp $file ; done
for file in $(find -name \*.h ) ; do sed -e "s/#include \"gmp\.h\"/#include \"mpir.h\"/g" $file > temp ; mv temp $file ; done
for file in $(find -name \*.cc) ; do sed -e "s/#include \"gmp\.h\"/#include \"mpir.h\"/g" $file > temp ; mv temp $file ; done
2009-02-12 10:24:24 +00:00

212 lines
3.9 KiB
C

/* nhgcd2
hgcd2 with stop condition suitable for sgcd and ngcd
*/
#include "mpir.h"
#include "gmp-impl.h"
#include "longlong.h"
/* Copied from mpn/generic/gcdext.c, and modified slightly to return
the remainder. */
/* Two-limb division optimized for small quotients. */
static inline mp_limb_t
div2 (mp_ptr rp,
mp_limb_t nh, mp_limb_t nl,
mp_limb_t dh, mp_limb_t dl)
{
mp_limb_t q = 0;
if ((mp_limb_signed_t) nh < 0)
{
int cnt;
for (cnt = 1; (mp_limb_signed_t) dh >= 0; cnt++)
{
dh = (dh << 1) | (dl >> (GMP_LIMB_BITS - 1));
dl = dl << 1;
}
while (cnt)
{
q <<= 1;
if (nh > dh || (nh == dh && nl >= dl))
{
sub_ddmmss (nh, nl, nh, nl, dh, dl);
q |= 1;
}
dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
dh = dh >> 1;
cnt--;
}
}
else
{
int cnt;
for (cnt = 0; nh > dh || (nh == dh && nl >= dl); cnt++)
{
dh = (dh << 1) | (dl >> (GMP_LIMB_BITS - 1));
dl = dl << 1;
}
while (cnt)
{
dl = (dh << (GMP_LIMB_BITS - 1)) | (dl >> 1);
dh = dh >> 1;
q <<= 1;
if (nh > dh || (nh == dh && nl >= dl))
{
sub_ddmmss (nh, nl, nh, nl, dh, dl);
q |= 1;
}
cnt--;
}
}
rp[0] = nl;
rp[1] = nh;
return q;
}
/* Reduces a,b until |a-b| fits in one limb + 1 bit. Constructs
matrix M. Returns 1 if we make progress, i.e. can perform at least
one subtraction. Otherwise returns zero.. */
int
mpn_nhgcd2 (mp_limb_t ah, mp_limb_t al, mp_limb_t bh, mp_limb_t bl,
struct ngcd_matrix1 *M)
{
mp_limb_t u00, u01, u10, u11;
if (ah < 2 || bh < 2)
return 0;
if (ah > bh || (ah == bh && al > bl))
{
sub_ddmmss (ah, al, ah, al, bh, bl);
if (ah < 2)
return 0;
u00 = u01 = u11 = 1;
u10 = 0;
}
else
{
sub_ddmmss (bh, bl, bh, bl, ah, al);
if (bh < 2)
return 0;
u00 = u10 = u11 = 1;
u01 = 0;
}
if (ah < bh)
goto subtract_a;
for (;;)
{
ASSERT (ah >= bh);
if (ah == bh)
break;
/* Subtract a -= q b, and multiply M from the right by (1 q ; 0
1), affecting the second column of M. */
ASSERT (ah > bh);
sub_ddmmss (ah, al, ah, al, bh, bl);
if (ah < 2)
break;
if (ah <= bh)
{
/* Use q = 1 */
u01 += u00;
u11 += u10;
}
else
{
mp_limb_t r[2];
mp_limb_t q = div2 (r, ah, al, bh, bl);
al = r[0]; ah = r[1];
if (ah < 2)
{
/* A is too small, but q is correct. */
u01 += q * u00;
u11 += q * u10;
break;
}
q++;
u01 += q * u00;
u11 += q * u10;
}
subtract_a:
ASSERT (bh >= ah);
if (ah == bh)
break;
/* Subtract b -= q a, and multiply M from the right by (1 0 ; q
1), affecting the first column of M. */
sub_ddmmss (bh, bl, bh, bl, ah, al);
if (bh < 2)
break;
if (bh <= ah)
{
/* Use q = 1 */
u00 += u01;
u10 += u11;
}
else
{
mp_limb_t r[2];
mp_limb_t q = div2 (r, bh, bl, ah, al);
bl = r[0]; bh = r[1];
if (bh < 2)
{
/* B is too small, but q is correct. */
u00 += q * u01;
u10 += q * u11;
break;
}
q++;
u00 += q * u01;
u10 += q * u11;
}
}
M->u[0][0] = u00; M->u[0][1] = u01;
M->u[1][0] = u10; M->u[1][1] = u11;
return 1;
}
/* Multiply (a;b) by M^{-1} = (r11, -r01; -r10, r00). Needs n limbs of
temporary storage. */
mp_size_t
mpn_ngcd_matrix1_vector (struct ngcd_matrix1 *M, mp_size_t n, mp_ptr ap, mp_ptr bp, mp_ptr tp)
{
mp_limb_t h0, h1;
/* Compute (a;b) <-- (u11 a - u01 b, -u10 a + u00 b) as
t = a
a *= u11
a -= u01 * b
b *= u00
b -= u10 * t
*/
MPN_COPY (tp, ap, n);
h0 = mpn_mul_1 (ap, ap, n, M->u[1][1]);
h1 = mpn_submul_1 (ap, bp, n, M->u[0][1]);
ASSERT (h0 == h1);
h0 = mpn_mul_1 (bp, bp, n, M->u[0][0]);
h1 = mpn_submul_1 (bp, tp, n, M->u[1][0]);
ASSERT (h0 == h1);
n -= (ap[n-1] | bp[n-1]) == 0;
return n;
}