📄 c_lip_impl.h
字号:
if (*a < *b) { long *t = a; a = b; b = t; }
sa = *a;
sb = *b;
sc = sa + sb;
if (sb < KARX) {
/* classic algorithm */
long *pc, i, *pb;
pc = c;
for (i = sc; i; i--) {
pc++;
*pc = 0;
}
pc = c;
pb = b;
for (i = sb; i; i--) {
pb++;
pc++;
zaddmul(*pb, pc, a);
}
}
else {
long hsa = (sa + 1) >> 1;
if (hsa < sb) {
/* normal case */
long *T1, *T2, *T3;
/* allocate space */
T1 = stk; stk += hsa + 2;
T2 = stk; stk += hsa + 2;
T3 = stk; stk += (hsa << 1) + 3;
if (stk-kmem > max_kmem) zhalt("internal error: kmem overflow");
/* compute T1 = a_lo + a_hi */
kar_fold(T1, a, hsa);
/* compute T2 = b_lo + b_hi */
kar_fold(T2, b, hsa);
/* recursively compute T3 = T1 * T2 */
kar_mul(T3, T1, T2, stk);
/* recursively compute a_hi * b_hi into high part of c */
/* and subtract from T3 */
{
long olda, oldb;
olda = a[hsa]; a[hsa] = sa-hsa;
oldb = b[hsa]; b[hsa] = sb-hsa;
kar_mul(c + (hsa << 1), a + hsa, b + hsa, stk);
kar_sub(T3, c + (hsa << 1));
a[hsa] = olda;
b[hsa] = oldb;
}
/* recursively compute a_lo*b_lo into low part of c */
/* and subtract from T3 */
*a = hsa;
*b = hsa;
kar_mul(c, a, b, stk);
kar_sub(T3, c);
*a = sa;
*b = sb;
/* finally, add T3 * NTL_RADIX^{hsa} to c */
kar_add(c, T3, hsa);
}
else {
/* degenerate case */
long *T;
T = stk; stk += sb + hsa + 1;
if (stk-kmem > max_kmem) zhalt("internal error: kmem overflow");
/* recursively compute b*a_hi into high part of c */
{
long olda;
olda = a[hsa]; a[hsa] = sa-hsa;
kar_mul(c + hsa, a + hsa, b, stk);
a[hsa] = olda;
}
/* recursively compute b*a_lo into T */
*a = hsa;
kar_mul(T, a, b, stk);
*a = sa;
/* fix-up result */
kar_fix(c, T, hsa);
}
}
/* normalize result */
while (c[sc] == 0 && sc > 1) sc--;
*c = sc;
}
#if (defined(NTL_SINGLE_MUL))
#define KARSX (36)
#else
#define KARSX (32)
#endif
static
void kar_sq(long *c, long *a, long *stk)
{
long sa, sc;
sa = *a;
sc = sa << 1;
if (sa < KARSX) {
/* classic algorithm */
long carry, i, j, *pc;
pc = c;
for (i = sc; i; i--) {
pc++;
*pc = 0;
}
carry = 0;
i = 0;
for (j = 1; j <= sa; j++) {
unsigned long uncar;
long t;
i += 2;
uncar = ((unsigned long) carry) + (((unsigned long) c[i-1]) << 1);
t = uncar & NTL_RADIXM;
zaddmulpsq(t, a[j], carry);
c[i-1] = t;
zaddmulsq(sa-j, c+i, a+j);
uncar = (c[i] << 1) + (uncar >> NTL_NBITS);
uncar += carry;
carry = uncar >> NTL_NBITS;
c[i] = uncar & NTL_RADIXM;
}
}
else {
long hsa = (sa + 1) >> 1;
long *T1, *T2, olda;
T1 = stk; stk += hsa + 2;
T2 = stk; stk += (hsa << 1) + 3;
if (stk-kmem > max_kmem) zhalt("internal error: kmem overflow");
kar_fold(T1, a, hsa);
kar_sq(T2, T1, stk);
olda = a[hsa]; a[hsa] = sa - hsa;
kar_sq(c + (hsa << 1), a + hsa, stk);
kar_sub(T2, c + (hsa << 1));
a[hsa] = olda;
*a = hsa;
kar_sq(c, a, stk);
kar_sub(T2, c);
*a = sa;
kar_add(c, T2, hsa);
}
while (c[sc] == 0 && sc > 1) sc--;
*c = sc;
}
void _ntl_zmul(_ntl_verylong a, _ntl_verylong b, _ntl_verylong *cc)
{
static _ntl_verylong mem = 0;
_ntl_verylong c = *cc;
if (!a || (a[0] == 1 && a[1] == 0) || !b || (b[0] == 1 && b[1] == 0)) {
_ntl_zzero(cc);
return;
}
if (a == b) {
if (a == c) {
_ntl_zcopy(a, &mem);
a = mem;
}
_ntl_zsq(a, cc);
}
else {
long aneg, bneg, sa, sb, sc;
if (a == c) {
_ntl_zcopy(a, &mem);
a = mem;
}
else if (b == c) {
_ntl_zcopy(b, &mem);
b = mem;
}
sa = *a;
if (sa < 0) {
*a = sa = -sa;
aneg = 1;
}
else
aneg = 0;
sb = *b;
if (*b < 0) {
*b = sb = -sb;
bneg = 1;
}
else
bneg = 0;
sc = sa + sb;
if (MustAlloc(c, sc)) {
_ntl_zsetlength(&c, sc);
*cc = c;
}
/* we optimize for *very* small numbers,
* avoiding all function calls and loops */
if (sa <= 3 && sb <= 3) {
long carry, d;
switch (sa) {
case 1:
switch (sb) {
case 1:
carry = 0;
zxmulp(c[1], a[1], b[1], carry);
c[2] = carry;
break;
case 2:
carry = 0;
d = a[1];
zxmulp(c[1], b[1], d, carry);
zxmulp(c[2], b[2], d, carry);
c[3] = carry;
break;
case 3:
carry = 0;
d = a[1];
zxmulp(c[1], b[1], d, carry);
zxmulp(c[2], b[2], d, carry);
zxmulp(c[3], b[3], d, carry);
c[4] = carry;
break;
}
break;
case 2:
switch (sb) {
case 1:
carry = 0;
d = b[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
c[3] = carry;
break;
case 2:
carry = 0;
d = b[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
c[3] = carry;
carry = 0;
d = b[2];
zaddmulp(c[2], a[1], d, carry);
zaddmulp(c[3], a[2], d, carry);
c[4] = carry;
break;
case 3:
carry = 0;
d = a[1];
zxmulp(c[1], b[1], d, carry);
zxmulp(c[2], b[2], d, carry);
zxmulp(c[3], b[3], d, carry);
c[4] = carry;
carry = 0;
d = a[2];
zaddmulp(c[2], b[1], d, carry);
zaddmulp(c[3], b[2], d, carry);
zaddmulp(c[4], b[3], d, carry);
c[5] = carry;
break;
}
break;
case 3:
switch (sb) {
case 1:
carry = 0;
d = b[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
zxmulp(c[3], a[3], d, carry);
c[4] = carry;
break;
case 2:
carry = 0;
d = b[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
zxmulp(c[3], a[3], d, carry);
c[4] = carry;
carry = 0;
d = b[2];
zaddmulp(c[2], a[1], d, carry);
zaddmulp(c[3], a[2], d, carry);
zaddmulp(c[4], a[3], d, carry);
c[5] = carry;
break;
case 3:
carry = 0;
d = b[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
zxmulp(c[3], a[3], d, carry);
c[4] = carry;
carry = 0;
d = b[2];
zaddmulp(c[2], a[1], d, carry);
zaddmulp(c[3], a[2], d, carry);
zaddmulp(c[4], a[3], d, carry);
c[5] = carry;
carry = 0;
d = b[3];
zaddmulp(c[3], a[1], d, carry);
zaddmulp(c[4], a[2], d, carry);
zaddmulp(c[5], a[3], d, carry);
c[6] = carry;
break;
}
}
if (c[sc] == 0) sc--;
if (aneg != bneg) sc = -sc;
*c = sc;
if (aneg) *a = -sa;
if (bneg) *b = -sb;
return;
}
#ifdef NTL_GMP_HACK
if (_ntl_gmp_hack && sa >= NTL_GMP_MUL_CROSS && sb >= NTL_GMP_MUL_CROSS) {
long gsa = L_TO_G(sa);
long gsb = L_TO_G(sb);
mp_limb_t *a_p, *b_p, *c_p, *end_p;;
NTL_GSPACE((gsa + gsb) << 1);
a_p = gspace_data;
b_p = a_p + gsa;
c_p = b_p + gsb;
end_p = c_p + (gsa + gsb);
lip_to_gmp(a+1, a_p, sa);
lip_to_gmp(b+1, b_p, sb);
if (!a_p[gsa-1]) gsa--;
if (!b_p[gsb-1]) gsb--;
end_p[-1] = 0;
end_p[-2] = 0;
if (gsa >= gsb)
mpn_mul(c_p, a_p, gsa, b_p, gsb);
else
mpn_mul(c_p, b_p, gsb, a_p, gsa);
gmp_to_lip(c+1, c_p, sc);
if (!c[sc]) sc--;
if (aneg != bneg) sc = -sc;
c[0] = sc;
if (aneg) *a = - *a;
if (bneg) *b = - *b;
return;
}
#endif
if (*a < KARX || *b < KARX) {
/* classic algorithm */
long i, *pc;
pc = c;
for (i = sc; i; i--) {
pc++;
*pc = 0;
}
pc = c;
if (*a >= *b) {
long *pb = b;
for (i = *pb; i; i--) {
pb++;
pc++;
zaddmul(*pb, pc, a);
}
}
else {
long *pa = a;
for (i = *pa; i; i--) {
pa++;
pc++;
zaddmul(*pa, pc, b);
}
}
while (c[sc] == 0 && sc > 1) sc--;
if (aneg != bneg && (sc != 1 || c[1] != 0)) sc = -sc;
c[0] = sc;
if (aneg) *a = - *a;
if (bneg) *b = - *b;
}
else {
/* karatsuba */
long n, hn, sp;
if (*a < *b)
n = *b;
else
n = *a;
sp = 0;
do {
hn = (n + 1) >> 1;
sp += (hn << 2) + 7;
n = hn+1;
} while (n >= KARX);
if (sp > max_kmem) {
if (max_kmem == 0)
kmem = (long *) malloc(sp * sizeof(long));
else
kmem = (long *) realloc(kmem, sp * sizeof(long));
max_kmem = sp;
if (!kmem) zhalt("out of memory in karatsuba");
}
kar_mul(c, a, b, kmem);
if (aneg != bneg && (*c != 1 || c[1] != 0)) *c = - *c;
if (aneg) *a = - *a;
if (bneg) *b = - *b;
}
}
}
void _ntl_zsq(_ntl_verylong a, _ntl_verylong *cc)
{
static _ntl_verylong mem = 0;
_ntl_verylong c = *cc;
long sa, aneg, sc;
if (!a || (a[0] == 1 && a[1] == 0)) {
_ntl_zzero(cc);
return;
}
if (a == c) {
_ntl_zcopy(a, &mem);
a = mem;
}
sa = *a;
if (*a < 0) {
*a = sa = -sa;
aneg = 1;
}
else
aneg = 0;
sc = (sa) << 1;
if (MustAlloc(c, sc)) {
_ntl_zsetlength(&c, sc);
*cc = c;
}
if (sa <= 3) {
long carry, d;
switch (sa) {
case 1:
carry = 0;
zxmulp(c[1], a[1], a[1], carry);
c[2] = carry;
break;
case 2:
carry = 0;
d = a[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
c[3] = carry;
carry = 0;
d = a[2];
zaddmulp(c[2], a[1], d, carry);
zaddmulp(c[3], a[2], d, carry);
c[4] = carry;
break;
case 3:
carry = 0;
d = a[1];
zxmulp(c[1], a[1], d, carry);
zxmulp(c[2], a[2], d, carry);
zxmulp(c[3], a[3], d, carry);
c[4] = carry;
carry = 0;
d = a[2];
zaddmulp(c[2], a[1], d, carry);
zaddmulp(c[3], a[2], d, carry);
zaddmulp(c[4], a[3], d, carry);
c[5] = carry;
carry = 0;
d = a[3];
zaddmulp(c[3], a[1], d, carry);
zaddmulp(c[4], a[2], d, carry);
zaddmulp(c[5], a[3], d, carry);
c[6] = carry;
break;
}
if (c[sc] == 0) sc--;
*c = sc;
if (aneg) *a = -sa;
return;
}
#ifdef NTL_GMP_HACK
if (_ntl_gmp_hack && sa >= NTL_GMP_SQR_CROSS) {
long gsa = L_TO_G(sa);
mp_limb_t *a_p, *c_p, *end_p;;
NTL_GSPACE(gsa + gsa + gsa);
a_p = gspace_data;
c_p = a_p + gsa;
end_p = c_p + (gsa + gsa);
lip_to_gmp(a+1, a_p, sa);
if (!a_p[gsa-1]) gsa--;
end_p[-1] = 0;
end_p[-2] = 0;
mpn_mul(c_p, a_p, gsa, a_p, gsa);
gmp_to_lip(c+1, c_p, sc);
if (!c[sc]) sc--;
c[0] = sc;
if (aneg) *a = - *a;
return;
}
#endif
if (sa < KARSX) {
/* classic algorithm */
long carry, i, j, *pc;
pc = c;
for (i = sc; i; i--) {
pc++;
*pc = 0;
}
carry = 0;
i = 0;
for (j = 1; j <= sa; j++) {
unsigned long uncar;
long t;
i += 2;
uncar = ((unsigned long) carry) + (((unsigned long) c[i-1]) << 1);
t = uncar & NTL_RADIXM;
zaddmulpsq(t, a[j], carry);
c[i-1] = t;
zaddmulsq(sa-j, c+i, a+j);
uncar = (c[i] << 1) + (uncar >> NTL_NBITS);
uncar
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -