?? zz.cpp
字號(hào):
#include <NTL/ZZ.h>
#include <NTL/vec_ZZ.h>
#include <NTL/new.h>
NTL_START_IMPL
const ZZ& ZZ::zero()
{
static ZZ z;
return z;
}
const ZZ& ZZ_expo(long e)
{
static ZZ expo_helper;
conv(expo_helper, e);
return expo_helper;
}
void AddMod(ZZ& x, const ZZ& a, long b, const ZZ& n)
{
static ZZ B;
conv(B, b);
AddMod(x, a, B, n);
}
void SubMod(ZZ& x, const ZZ& a, long b, const ZZ& n)
{
static ZZ B;
conv(B, b);
SubMod(x, a, B, n);
}
void SubMod(ZZ& x, long a, const ZZ& b, const ZZ& n)
{
static ZZ A;
conv(A, a);
SubMod(x, A, b, n);
}
// ****** input and output
static long iodigits = 0;
static long ioradix = 0;
// iodigits is the greatest integer such that 10^{iodigits} < NTL_WSP_BOUND
// ioradix = 10^{iodigits}
static void InitZZIO()
{
long x;
x = (NTL_WSP_BOUND-1)/10;
iodigits = 0;
ioradix = 1;
while (x) {
x = x / 10;
iodigits++;
ioradix = ioradix * 10;
}
if (iodigits <= 0) Error("problem with I/O");
}
istream& operator>>(istream& s, ZZ& x)
{
long c;
long cval;
long sign;
long ndigits;
long acc;
static ZZ a;
if (!s) Error("bad ZZ input");
if (!iodigits) InitZZIO();
a = 0;
SkipWhiteSpace(s);
c = s.peek();
if (c == '-') {
sign = -1;
s.get();
c = s.peek();
}
else
sign = 1;
cval = CharToIntVal(c);
if (cval < 0 || cval > 9) Error("bad ZZ input");
ndigits = 0;
acc = 0;
while (cval >= 0 && cval <= 9) {
acc = acc*10 + cval;
ndigits++;
if (ndigits == iodigits) {
mul(a, a, ioradix);
add(a, a, acc);
ndigits = 0;
acc = 0;
}
s.get();
c = s.peek();
cval = CharToIntVal(c);
}
if (ndigits != 0) {
long mpy = 1;
while (ndigits > 0) {
mpy = mpy * 10;
ndigits--;
}
mul(a, a, mpy);
add(a, a, acc);
}
if (sign == -1)
negate(a, a);
x = a;
return s;
}
// The class _ZZ_local_stack should be defined in an empty namespace,
// but since I don't want to rely on namespaces, we just give it a funny
// name to avoid accidental name clashes.
struct _ZZ_local_stack {
long top;
long alloc;
long *elts;
_ZZ_local_stack() { top = -1; alloc = 0; elts = 0; }
~_ZZ_local_stack() { }
long pop() { return elts[top--]; }
long empty() { return (top == -1); }
void push(long x);
};
void _ZZ_local_stack::push(long x)
{
if (alloc == 0) {
alloc = 100;
elts = (long *) NTL_MALLOC(alloc, sizeof(long), 0);
}
top++;
if (top + 1 > alloc) {
alloc = 2*alloc;
elts = (long *) NTL_REALLOC(elts, alloc, sizeof(long), 0);
}
if (!elts) {
Error("out of space in ZZ output");
}
elts[top] = x;
}
static
void PrintDigits(ostream& s, long d, long justify)
{
static char *buf = 0;
if (!buf) {
buf = (char *) NTL_MALLOC(iodigits, 1, 0);
if (!buf) Error("out of memory");
}
long i = 0;
while (d) {
buf[i] = IntValToChar(d % 10);
d = d / 10;
i++;
}
if (justify) {
long j = iodigits - i;
while (j > 0) {
s << "0";
j--;
}
}
while (i > 0) {
i--;
s << buf[i];
}
}
ostream& operator<<(ostream& s, const ZZ& a)
{
static ZZ b;
static _ZZ_local_stack S;
long r;
long k;
if (!iodigits) InitZZIO();
b = a;
k = sign(b);
if (k == 0) {
s << "0";
return s;
}
if (k < 0) {
s << "-";
negate(b, b);
}
do {
r = DivRem(b, b, ioradix);
S.push(r);
} while (!IsZero(b));
r = S.pop();
PrintDigits(s, r, 0);
while (!S.empty()) {
r = S.pop();
PrintDigits(s, r, 1);
}
return s;
}
long GCD(long a, long b)
{
long u, v, t, x;
if (a < 0) {
if (a < -NTL_MAX_LONG) Error("GCD: integer overflow");
a = -a;
}
if (b < 0) {
if (b < -NTL_MAX_LONG) Error("GCD: integer overflow");
b = -b;
}
if (b==0)
x = a;
else {
u = a;
v = b;
do {
t = u % v;
u = v;
v = t;
} while (v != 0);
x = u;
}
return x;
}
void XGCD(long& d, long& s, long& t, long a, long b)
{
long u, v, u0, v0, u1, v1, u2, v2, q, r;
long aneg = 0, bneg = 0;
if (a < 0) {
if (a < -NTL_MAX_LONG) Error("XGCD: integer overflow");
a = -a;
aneg = 1;
}
if (b < 0) {
if (b < -NTL_MAX_LONG) Error("XGCD: integer overflow");
b = -b;
bneg = 1;
}
u1=1; v1=0;
u2=0; v2=1;
u = a; v = b;
while (v != 0) {
q = u / v;
r = u % v;
u = v;
v = r;
u0 = u2;
v0 = v2;
u2 = u1 - q*u2;
v2 = v1- q*v2;
u1 = u0;
v1 = v0;
}
if (aneg)
u1 = -u1;
if (bneg)
v1 = -v1;
d = u;
s = u1;
t = v1;
}
long InvMod(long a, long n)
{
long d, s, t;
XGCD(d, s, t, a, n);
if (d != 1) Error("InvMod: inverse undefined");
if (s < 0)
return s + n;
else
return s;
}
long PowerMod(long a, long ee, long n)
{
long x, y;
unsigned long e;
if (ee < 0)
e = - ((unsigned long) ee);
else
e = ee;
x = 1;
y = a;
while (e) {
if (e & 1) x = MulMod(x, y, n);
y = MulMod(y, y, n);
e = e >> 1;
}
if (ee < 0) x = InvMod(x, n);
return x;
}
long ProbPrime(long n, long NumTests)
{
long m, x, y, z;
long i, j, k;
if (n <= 1) return 0;
if (n == 2) return 1;
if (n % 2 == 0) return 0;
if (n == 3) return 1;
if (n % 3 == 0) return 0;
if (n == 5) return 1;
if (n % 5 == 0) return 0;
if (n == 7) return 1;
if (n % 7 == 0) return 0;
if (n >= NTL_SP_BOUND) {
return ProbPrime(to_ZZ(n), NumTests);
}
m = n - 1;
k = 0;
while((m & 1) == 0) {
m = m >> 1;
k++;
}
// n - 1 == 2^k * m, m odd
for (i = 0; i < NumTests; i++) {
do {
x = RandomBnd(n);
} while (x == 0);
// x == 0 is not a useful candidtae for a witness!
if (x == 0) continue;
z = PowerMod(x, m, n);
if (z == 1) continue;
j = 0;
do {
y = z;
z = MulMod(y, y, n);
j++;
} while (j != k && z != 1);
if (z != 1 || y != n-1) return 0;
}
return 1;
}
long MillerWitness(const ZZ& n, const ZZ& x)
{
ZZ m, y, z;
long j, k;
if (x == 0) return 0;
add(m, n, -1);
k = MakeOdd(m);
// n - 1 == 2^k * m, m odd
PowerMod(z, x, m, n);
if (z == 1) return 0;
j = 0;
do {
y = z;
SqrMod(z, y, n);
j++;
} while (j != k && z != 1);
if (z != 1) return 1;
add(y, y, 1);
if (y != n) return 1;
return 0;
}
// ComputePrimeBound computes a reasonable bound for trial
// division in the Miller-Rabin test.
// It is computed a bit on the "low" side, since being a bit
// low doesn't hurt much, but being too high can hurt a lot.
static
long ComputePrimeBound(long bn)
{
long wn = (bn+NTL_ZZ_NBITS-1)/NTL_ZZ_NBITS;
long fn;
if (wn <= 36)
fn = wn/4 + 1;
else
fn = long(1.67*sqrt(double(wn)));
long prime_bnd;
if (NumBits(bn) + NumBits(fn) > NTL_SP_NBITS)
prime_bnd = NTL_SP_BOUND;
else
prime_bnd = bn*fn;
return prime_bnd;
}
long ProbPrime(const ZZ& n, long NumTrials)
{
if (n <= 1) return 0;
if (n.SinglePrecision()) {
return ProbPrime(to_long(n), NumTrials);
}
long prime_bnd = ComputePrimeBound(NumBits(n));
PrimeSeq s;
long p;
p = s.next();
while (p && p < prime_bnd) {
if (rem(n, p) == 0)
return 0;
p = s.next();
}
ZZ W;
W = 2;
// first try W == 2....the exponentiation
// algorithm runs slightly faster in this case
if (MillerWitness(n, W))
return 0;
long i;
for (i = 0; i < NumTrials; i++) {
do {
RandomBnd(W, n);
} while (W == 0);
// W == 0 is not a useful candidate for a witness!
if (MillerWitness(n, W))
return 0;
}
return 1;
}
void RandomPrime(ZZ& n, long l, long NumTrials)
{
if (l <= 1)
Error("RandomPrime: l out of range");
if (l == 2) {
if (RandomBnd(2))
n = 3;
else
n = 2;
return;
}
do {
RandomLen(n, l);
if (!IsOdd(n)) add(n, n, 1);
} while (!ProbPrime(n, NumTrials));
}
void NextPrime(ZZ& n, const ZZ& m, long NumTrials)
{
ZZ x;
if (m <= 2) {
n = 2;
return;
}
x = m;
while (!ProbPrime(x, NumTrials))
add(x, x, 1);
n = x;
}
long NextPrime(long m, long NumTrials)
{
long x;
if (m <= 2)
return 2;
x = m;
while (x < NTL_SP_BOUND && !ProbPrime(x, NumTrials))
x++;
if (x >= NTL_SP_BOUND)
Error("NextPrime: no more primes");
return x;
}
long NextPowerOfTwo(long m)
{
long k;
unsigned long n, um;
if (m < 0) return 0;
um = m;
k = 0;
while (n < um) {
n = n << 1;
k++;
}
if (k >= NTL_BITS_PER_LONG-1)
Error("NextPowerOfTwo: overflow");
}
long NumBits(long a)
{
unsigned long aa;
if (a < 0)
aa = - ((unsigned long) a);
else
aa = a;
long k = 0;
while (aa) {
k++;
aa = aa >> 1;
}
return k;
}
long bit(long a, long k)
{
unsigned long aa;
if (a < 0)
aa = - ((unsigned long) a);
else
aa = a;
if (k < 0 || k >= NTL_BITS_PER_LONG)
return 0;
else
return long((aa >> k) & 1);
}
long divide(ZZ& q, const ZZ& a, const ZZ& b)
{
static ZZ qq, r;
if (IsZero(b)) {
if (IsZero(a)) {
clear(q);
return 1;
}
else
return 0;
}
if (IsOne(b)) {
q = a;
return 1;
}
DivRem(qq, r, a, b);
if (!IsZero(r)) return 0;
q = qq;
}
long divide(const ZZ& a, const ZZ& b)
{
static ZZ r;
if (IsZero(b)) return IsZero(a);
if (IsOne(b)) return 1;
rem(r, a, b);
return IsZero(r);
}
long divide(ZZ& q, const ZZ& a, long b)
{
static ZZ qq;
if (!b) {
if (IsZero(a)) {
clear(q);
return 1;
}
else
return 0;
}
if (b == 1) {
q = a;
return 1;
}
long r = DivRem(qq, a, b);
if (r) return 0;
q = qq;
return 1;
}
long divide(const ZZ& a, long b)
{
if (!b) return IsZero(a);
if (b == 1) {
return 1;
}
long r = rem(a, b);
return (r == 0);
}
long RandomPrime_long(long l, long NumTrials)
{
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -