📄 c_lip.c
字号:
#define KARSX (36)#else#define KARSX (32) #endifstaticvoid 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 += carry; carry = uncar >> NTL_NBITS; c[i] = uncar & NTL_RADIXM; } while (c[sc] == 0 && sc > 1) sc--; c[0] = sc; if (aneg) *a = - *a; } else { /* karatsuba */ long n, hn, sp; n = *a; sp = 0; do { hn = (n + 1) >> 1; sp += hn + hn + hn + 5; n = hn+1; } while (n >= KARSX); 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_sq(c, a, kmem); if (aneg) *a = - *a; }}long _ntl_zsdiv(_ntl_verylong a, long d, _ntl_verylong *bb){ long sa; _ntl_verylong b = *bb; if (!d) { zhalt("division by zero in _ntl_zsdiv"); } if (!a) { _ntl_zzero(bb); return (0); } if (d == 2) { long is_odd = a[1] & 1; long fix = (a[0] < 0) & is_odd; _ntl_zrshift(a, 1, bb); if (fix) _ntl_zsadd(*bb, -1, bb); return is_odd; } if ((sa = a[0]) < 0) sa = (-sa); _ntl_zsetlength(&b, sa); if (a == *bb) a = b; *bb = b; if ((d >= NTL_RADIX) || (d <= -NTL_RADIX)) { static _ntl_verylong zd = 0; static _ntl_verylong zb = 0; _ntl_zintoz(d, &zb); _ntl_zdiv(a, zb, &b, &zd); *bb = b; return (_ntl_ztoint(zd)); } else { long den = d; double deninv; long carry = 0; long i; long flag = (*a < 0 ? 2 : 0) | (den < 0 ? 1 : 0); if (den < 0) den = -den; deninv = (double)1/den; if (a[sa] < den && sa > 1) carry = a[sa--]; for (i = sa; i; i--) { zdiv21(carry, a[i], den, deninv, b[i]); } while ((sa > 1) && (!(b[sa]))) sa--; b[0] = sa; if (flag) { if (flag <= 2) { if (!carry) _ntl_znegate(&b); else { _ntl_zsadd(b, 1, &b); b[0] = -b[0]; if (flag == 1) carry = carry - den; else carry = den - carry; *bb = b; } } else carry = -carry; } return (carry); }}long _ntl_zsmod(_ntl_verylong a, long d){ long sa; if (!a) { return (0); } if (d == 2) return (a[1] & 1); if (!d) { zhalt("division by zero in _ntl_zsdiv"); } if ((sa = a[0]) < 0) sa = (-sa); if ((d >= NTL_RADIX) || (d <= -NTL_RADIX)) { static _ntl_verylong zd = 0; static _ntl_verylong zb = 0; _ntl_zintoz(d, &zb); _ntl_zmod(a, zb, &zd); return (_ntl_ztoint(zd)); } else { long den = d; double deninv; long carry = 0; long i; long flag = (*a < 0 ? 2 : 0) | (den < 0 ? 1 : 0); if (den < 0) den = -den; deninv = (double)1/den; if (a[sa] < den && sa > 1) carry = a[sa--]; for (i = sa; i; i--) { zrem21(carry, a[i], den, deninv); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -