- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我最近试图将一堆(最多 10^5)非常小的数字(10^-4 的数量级)相互相乘,所以我将以 10^-(4*10^ 的数量级结束5) 不适合任何变量。
我的方法如下:
这是针对少数不同情况多次完成的。最后我想知道的是一个这样的产品占所有产品总和的分数,精度可达 10^-6。为此,在第 2 步和第 3 步之间,将结果添加到一个总和数组中,该数组最后也是 iFFT。由于要求的精度很低,所以我没有对多项式进行除法,而是只取前几个数为整数。
我的问题如下:FFT 和/或 iFFT 无法正常工作!我是新手,只实现过一次 FFT。我的代码如下(C++14):
#include <cstdio>
#include <vector>
#include <cmath>
#include <complex>
#include <iostream>
using namespace std;
const double PI = 4*atan(1.0);
vector<complex<double>> FFT (vector<complex<double>> A, long N)
{
vector<complex<double>> Ans(0);
if(N==1)
{
Ans.push_back(A[0]);
return Ans;
}
vector<complex<double>> even(N/2);
vector<complex<double>> odd(N/2);
for(long i=0; i<(N/2); i++)
{
even[i] = A[2*i];
odd[i] = A[2*i+1];
}
vector<complex<double>> L1 = FFT(even, N/2);
vector<complex<double>> L2 = FFT(odd, N/2);
for(long i=0; i<N; i++)
{
complex<double> z(cos(2*PI*i/N),sin(2*PI*i/N));
long k = i%(N/2);
Ans.push_back(L1[k] + z*L2[k]);
}
return Ans;
}
vector<complex<double>> iFFT (vector<complex<double>> A, long N)
{
vector<complex<double>> Ans(0);
if(N==1)
{
Ans.push_back(A[0]);
return Ans;
}
vector<complex<double>> even(N/2);
vector<complex<double>> odd(N/2);
for(long i=0; i<(N/2); i++)
{
even[i] = A[2*i];
odd[i] = A[2*i+1];
}
vector<complex<double>> L1 = FFT(even, N/2);
vector<complex<double>> L2 = FFT(odd, N/2);
for(long i=0; i<N; i++)
{
complex<double> z(cos(-2*PI*i/N),sin(-2*PI*i/N));
complex<double> inv(double(1.0/N), 0);
long k = i%(N/2);
Ans.push_back(inv*(L1[k]+z*L2[k]));
}
return Ans;
}
vector<complex<double>> PMult (vector<complex<double>> A, vector<complex<double>> B, long L)
{
vector<complex<double>> Ans(L);
for(int i=0; i<L; i++)
{
Ans[i] = A[i]*B[i];
}
return Ans;
}
vector<complex<double>> DtoA (double x)
{
vector<complex<double>> ans(8);
long X = long(x*10000000);
ans[0] = complex<double>(double(X%10), 0.0); X/=10;
ans[1] = complex<double>(double(X%10), 0.0); X/=10;
ans[2] = complex<double>(double(X%10), 0.0); X/=10;
ans[3] = complex<double>(double(X%10), 0.0); X/=10;
ans[4] = complex<double>(double(X%10), 0.0); X/=10;
ans[5] = complex<double>(double(X%10), 0.0); X/=10;
ans[6] = complex<double>(double(X%10), 0.0); X/=10;
ans[7] = complex<double>(double(X%10), 0.0);
return ans;
}
int main()
{
vector<vector<complex<double>>> W;
int T, N, M;
double p;
scanf("%d", &T);
while( T-- )
{
scanf("%d %d", &N, &M);
W.resize(N);
for(int i=0; i<N; i++)
{
cin >> p;
W[i] = FFT(DtoA(p),8);
for(int j=1; j<M; j++)
{
cin >> p;
W[i] = PMult(W[i], FFT(DtoA(p),8), 8);
}
}
vector<complex<double>> Sum(8);
for(int j=0; j<8; j++) Sum[j]=W[0][j];
for(int i=1; i<N; i++)
{
for(int j=0; j<8; j++)
{
Sum[j]+=W[i][j];
}
}
W[0]=iFFT(W[0],8);
Sum=iFFT(Sum, 8);
long X=0;
long Y=0;
int a;
for(a=0; Sum[a].real()!=0; a++);
for(int i=a; i<8; i++)
{
Y*=10;
Y=Y+long(Sum[i].real());
}
for(int i=a; i<8; i++)
{
X*=10;
X=X+long(W[0][i].real());
}
double ans = 0.0;
if(Y) ans=double(X)/double(Y);
printf("%.7f\n", ans);
}
}
我观察到的是,对于除一个条目外仅由零组成的数组,FFT 返回一个包含多个非空条目的数组。此外,在 iFFT 完成后,结果仍然包含虚部非零的条目。
有人可以找到错误或向我提供可以使解决方案更容易的提示吗?因为我希望它快,所以我不想做一个天真的乘法。 Karatsuba 的算法会不会更好,因为我不需要复数?
最佳答案
我检查了我的 FFT 的旧 Java 实现(抱歉代码很糟糕)。我在您的 FFT 和 DtoA 函数中发现了以下内容:
a + b * c
,后半部分的形式为 a - b * c
.下面的代码效率不高,但应该很清楚。
#include <iostream>
#include <vector>
#include <complex>
#include <exception>
#include <cmath>
using namespace std;
vector<complex<double>> fft(const vector<complex<double>> &x) {
int N = x.size();
// base case
if (N == 1) return vector<complex<double>> { x[0] };
// radix 2 Cooley-Tukey FFT
if (N % 2 != 0) { throw new std::exception(); }
// fft of even terms
vector<complex<double>> even, odd;
for (int k = 0; k < N/2; k++) {
even.push_back(x[2 * k]);
odd.push_back(x[2 * k + 1]);
}
vector<complex<double>> q = fft(even);
vector<complex<double>> r = fft(odd);
// combine
vector<complex<double>> y;
for (int k = 0; k < N/2; k++) {
double kth = -2 * k * M_PI / N;
complex<double> wk = complex<double>(cos(kth), sin(kth));
y.push_back(q[k] + (wk * r[k]));
}
for (int k = 0; k < N/2; k++) {
double kth = -2 * k * M_PI / N;
complex<double> wk = complex<double>(cos(kth), sin(kth));
y.push_back(q[k] - (wk * r[k])); // you didn't do this
}
return y;
}
vector<complex<double>> DtoA (double x)
{
vector<complex<double>> ans(8);
long X = long(x*100000000); // a 0 was missing here
ans[7] = complex<double>(double(X%10), 0.0); X/=10;
ans[6] = complex<double>(double(X%10), 0.0); X/=10;
ans[5] = complex<double>(double(X%10), 0.0); X/=10;
ans[4] = complex<double>(double(X%10), 0.0); X/=10;
ans[3] = complex<double>(double(X%10), 0.0); X/=10;
ans[2] = complex<double>(double(X%10), 0.0); X/=10;
ans[1] = complex<double>(double(X%10), 0.0); X/=10;
ans[0] = complex<double>(double(X%10), 0.0);
return ans;
}
int main ()
{
double n = 0.1234;
auto nComplex = DtoA(n);
for (const auto &e : nComplex) {
std::cout << e << " ";
}
std::cout << std::endl;
try {
auto nFFT = fft(nComplex);
for (const auto &e : nFFT) {
std::cout << e << " ";
}
}
catch (const std::exception &e) {
std::cout << "exception" << std::endl;
}
return 0;
}
程序输出(我用Octave查了一下,是一样的):
(1,0) (2,0) (3,0) (4,0) (0,0) (0,0) (0,0) (0,0)
(10,0) (-0.414214,-7.24264) (-2,2) (2.41421,-1.24264) (-2,0) (2.41421,1.24264) (-2,-2) (-0.414214,7.24264)
希望这对您有所帮助。
编辑:
关于逆FFT,你可以证明
iFFT(x) = (1 / N) conjugate( FFT( conjugate(x) ) )
其中 N 是数组 x 中元素的数量。所以你可以使用 fft 函数来计算 ifft:
vector<complex<double>> ifft(const vector<complex<double>> &vec) {
std::vector<complex<double>> conj;
for (const auto &e : vec) {
conj.push_back(std::conj(e));
}
std::vector<complex<double>> vecFFT = fft(conj);
std::vector<complex<double>> result;
for (const auto &e : vecFFT) {
result.push_back(std::conj(e) / static_cast<double>(vec.size()));
}
return result;
}
这里是修改后的主体:
int main ()
{
double n = 0.1234;
auto nComplex = DtoA(n);
for (const auto &e : nComplex) {
std::cout << e << " ";
}
std::cout << std::endl;
auto nFFT = fft(nComplex);
for (const auto &e : nFFT)
std::cout << e << " ";
std::cout << std::endl;
auto iFFT = ifft(nFFT);
for (const auto &e : iFFT)
std::cout << e << " ";
return 0;
}
和输出:
(1,0) (2,0) (3,0) (4,0) (0,0) (0,0) (0,0) (0,0)
(10,0) (-0.414214,-7.24264) (-2,2) (2.41421,-1.24264) (-2,0) (2.41421,1.24264) (-2,-2) (-0.414214,7.24264)
(1,-0) (2,-1.08163e-16) (3,7.4688e-17) (4,2.19185e-16) (0,-0) (0,1.13882e-16) (0,-7.4688e-17) (0,-2.24904e-16)
请注意,像 1e-16
这样的数字几乎是 0( double 在硬件上并不完美)。
关于c++ - 在大数乘法上使用 FFT 的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31369856/
我已经花了不少时间编写我的代码(它不起作用)。这是一个欧拉计划问题,其中给定一个非常大的和来查找,然后要求打印该和的前十位数字。 (问题可以在这里找到:https://projecteuler.net
我正在构建一个基于大整数的 C 库。基本上,我正在寻找一种快速算法来将二进制表示中的任何整数转换为十进制数 我看到了 JDK 的 Biginteger.toString() 实现,但对我来说它看起来很
C++ 编程新手。有没有办法使代码更好,使其没有重复代码。 if (totalDistance < pow(10, 3)) { cout << "\nTotal (approx) travel
我正在开发一个 3D 太空游戏,它使用了大量的数学公式、导航、缓动效果、旋转、行星之间的巨大距离、物体质量等等...... 我的问题是使用数学的最佳方法是什么。我应该将所有内容都计算为整数并获得非
我尝试用 JS 的取模函数计算,但没有得到正确的结果(应该是 1)。这是一段硬编码的代码。 var checkSum = 210501700012345678131468; alert(checkSu
美好的一天我正在尝试对 10000 个数字使用快速排序,但它给我堆栈溢出错误。它适用于随机数,但不适用于递减和递增的数字。 '谢谢 void quickSort(long* array, long s
在 Codewars 上找到这个。该函数接受两个参数 A 和 B,并返回 A^B 的最后一位。下面的代码通过了前两个测试用例,但不会通过下一个测试用例。 def last_digit(n1, n2):
复制代码 代码如下: #include <stdio.h> #include <string.h> #include <stdlib.h> #include
我需要一些帮助来决定什么更好 性能 明智的。 我正在与 一起工作bigints (超过 500 万位)并且大部分计算(如果不是全部)都在将当前 bigint 加倍。所以我想知道 是否更好乘每个单元格(
我正在对字符串执行一些 mod 算术类型的操作,其中每个字符都会获得特定的初始值(取决于其 ascii)和字符串中的位置。这些数字变得非常大,因为它们的初始值为 (ascii)*26^charPos。
这个问题在这里已经有了答案: Calculating pow(a,b) mod n (14 个答案) 关闭 6 年前。 在 Javascript 中是否有获取大数模数的技巧。我用 modulo(7,
我一直在努力为我的大学完成以下作业。到目前为止,我已经多次在这项作业上得到帮助(我真的很感激)。 由于这是大学作业,我希望能提供非直接的答案,这些答案可以通过不直接解决我的作业的示例来解释概念。 作业
我正在处理无法四舍五入的大量数字。使用 Lua 的标准数学库,似乎没有方便的方法来保持超出某些内部限制的精度。我还看到有几个库可以加载以处理大数字: http://oss.digirati.com.b
我有一个数据文件 (csv) Nilsimsa哈希值。其中一些可能长达 80 个字符。我希望在 Python 中阅读它们以完成数据分析任务。有没有办法在不丢失信息的情况下在python中导入数据? 编
我是一名优秀的程序员,十分优秀!