类结构:带哑元节点的双向循环链表
void BigInt::FFT(Complex a[], int n, int flag, int rev[])
{
const double pi = acos(-1.0); //常数π
for (int i = 0; i < n; i++)
{
if (i < rev[i]) //保证只交换一次
swap(a[i], a[rev[i]]);
}
for (int d = 1; d < n; d <<= 1) //当前区间长度d
{
int t = d << 1; //t=2d
double tt = pi / d;
Complex w0(cos(tt), sin(tt) * flag); //单位根
for (int i = 0; i < n; i += t) //合并区间到第i位
{
Complex w(1, 0); //w=w0^(0~d-1)
for (int j = 0; j < d; j++, w = w * w0) //计算一个区间内的d个根
{
Complex x = a[i + j], y = w * a[i + j + d];
a[i + j] = x + y; //蝴蝶变换
a[i + j + d] = x - y;
}
}
}
if (flag == -1) //IDFT
for (int i = 0; i < n; i++)
a[i].r /= n;
}
BigInt BigInt::operator/(const BigInt& b) //除
{
BigInt t;
int cp = compare(b);
if (cp <= 0)
{
if (cp < 0)t.push_back(0);
else t.push_back(1);
return t;
}
int dDigit = length - b.length;
int len = dDigit + 16; //计算的倒数的有效位数
int l1 = 16, l2 = 32, l4 = 64;
long double d = 0, e = 1;
char* b1 = new char[b.length + 5]; //存一下b 多申请一些
memset(b1, 0, b.length);
Node* p = b.head->next;
for (int i = 0; i < b.length; i++)
{
b1[i] = p->data;
p = p->next;
}
for (int i = 0; i < 2 * base; i++)
{
if (i == b.length)break;
d = d + b1[i] * e;
e *= 0.1;
}
d = 1.0 * base / d;
if (d < base)
{
for (int i = 0; i <= l1; i++)
{
bpi[i] = d;
d = (d - bpi[i]) * base;
}
bpi[l1 - 1] += bpi[l1] >= base / 2; //四舍五入
}
else
{
bpi[0] = base;
}
bool first = true; //用于末几位单独迭代
while (l1 < len) //每次迭代区间长度l4
{
cir:
;
int n = 1; //系数总位数
int bit = 0; //n的二进制位数
while (n < l4) //位数凑成2的幂次
{
n <<= 1;
bit++;
}
int* rev = new int[n + 5]; //储存要交换的数位置
memset(rev, 0, 4 * n); //不是全局变量 记得赋0
for (int i = 0; i < n; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1)); //二进制逆序
Complex* A = new Complex[n + 5];
Complex* B = new Complex[n + 5];
memset(A, 0, sizeof(Complex) * l4);
memset(B, 0, sizeof(Complex) * l4);
for (int i = 0; i < l2; i++)
{
if (i == b.length)break;
A[i].r = b1[i];
}
for (int i = 0; i < l1; i++)
{
B[i].r = bpi[i];
}
FFT(A, l4, 1, rev);
FFT(B, l4, 1, rev);
for (int i = 0; i < l4; i++)
{
A[i] = A[i] * B[i]; //和乘法的不一样
A[i].r = 2 * base - A[i].r; //所以展开写
A[i].i = -A[i].i;
B[i] = A[i] * B[i];
}
FFT(B, l4, -1, rev);
C[l4] = 0;
for (int i = l4 - 1; i >= 0; i--)
{
C[i] = (long long)(floor(B[i].r + 0.5)) + C[i + 1] / base;
C[i + 1] %= base;
if (C[i + 1] < 0) //借位
C[i + 1] += base, C[i]--;
}
if (C[0] >= base) //进位
{
bpi[0] = C[0] / base;
C[0] %= base;
for (int i = 1; i < l2; i++)
bpi[i] = C[i - 1];
bpi[l2 - 1] += C[l2 - 1] >= base / 2; //四舍五入
}
else
{
for (int i = 0; i < l2; i++)
bpi[i] = C[i];
bpi[l2 - 1] = C[l2] > 4;
}
l1 <<= 1;
l2 <<= 1;
l4 <<= 1;
delete[] rev;
delete[] A;
delete[] B;
}
if (first) //末尾几位有误差 再迭代一次
{
first = false;
l1 >>= 1;
l2 >>= 1;
l4 >>= 1;
goto cir;
}
BigInt bd;
for (int i = 0; i < len; i++)
bd.push_back(bpi[i]); //倒数1/b
hasCarried = false; //乘法过程中是否有进位(res)
t = *this * bd; //决定答案的真实位数
if (hasCarried)
t.updataDigit(dDigit + 1);
else
t.updataDigit(dDigit);
delete[] b1;
BigInt a2, t0(t); //反乘验证
t.head->pre->data++; //商+1
t.carry(); //进位
a2 = t * b; //+nlgn
if (a2.compare(*this) <= 0) //商+1反乘都小于等于被除数
return t; //返回+1的
return t0; //返回原来的
}
竖式模拟