我是一名电路设计师(不是软件向导),过去9个月一直致力于数值算法.作为评估算法有效性的一种方法,我会监控收敛解决方案所需的时间.
大约6个月前,我发现我声明变量的方式会对程序运行所需的时间产生巨大影响.例如,简单地重新排列声明(如下所示)可以使运行代码所需的时间加倍.简单地改变阵列的长度也会同样影响问题.
int N, j, Iter;
long double RealZero, RealErr, QuadIterErr, QuadX;
long double TUV[3], QuadQP[102], RealQP[102];
bool Updated;
int N, j, Iter;
long double RealZero, RealErr, QuadIterErr, QuadX;
long double QuadQP[102], RealQP[102];
bool Updated;
long double TUV[3];
Run Code Online (Sandbox Code Playgroud)
我最初认为我有某种错误,但我找不到它.除了速度之外,我没有看到任何其他异常,无论代码运行缓慢还是快速,我都得到相同的结果.
我找到了一些与包装长双打有关的问题的讨论,但我不理解任何一个,他们从未说过如何解决他们正在讨论的问题.
有人可以给我一些关于这里可能会发生什么以及如何解决它的见解?
我需要的是一致性而不是我需要的速度.我没有使用任何速度优化器(默认编译器设置),我使用的是C++ Builder XE3.我没有使用#pragma pack(正如有人问的那样).
根据注释,我设置了慢速和快速执行的声明,并比较了所有长双变量的基址.无论是慢速还是快速,地址都以0,4,8或C结尾.
我是EE,而不是代码专家,所以请在这里请耐心等待.
我正在使用Embarcadero C++ Builder(XE3).
我有一个FFT算法,它对复数进行了大量的操作.我发现如果我绕过Embarcadero的复杂数学库,并在我自己的代码中进行所有计算,我的FFT运行速度将快4.5倍.这里显示的4个操作都需要过多的时间.
#include <dinkumware\complex>
#define ComplexD std::complex<double>
ComplexD X, Y, Z, FFTInput[1024];
double x, y;
Z = X * Y;
x = X.real();
y = X.imag();
Z = ComplexD(x,y);
Run Code Online (Sandbox Code Playgroud)
用我自己的交叉乘法替换乘法将我的执行时间减半.然而,我关心的是我访问输入数组的实部和虚部的方式.我这样做:
double *Input;
Input = reinterpret_cast<double *>(FFTInput);
// Then these statements are equivalent.
x = FFTInput[n].real();
y = FFTInput[n].imag();
x = Input[2*n];
y = Input[2*n+1];
Run Code Online (Sandbox Code Playgroud)
这样做可以将执行时间再缩短一半,但我不知道这种reinterpret_cast是否是明智之举.我可以将输入数组更改为两个双精度而不是复数,但我在许多程序中使用此FFT并且不想重写所有内容.
这个reinterpret_cast好吗,还是我有内存问题?另外,有没有办法让Embarcadero复杂的数学函数运行得更快?最后,虽然它对我来说不是非常重要,但是这个reinterpret_cast是否可移植?
我是电路设计师,而不是软件工程师,所以我不知道如何追踪这个问题.
我正在使用一些IIR过滤器代码,当我通过过滤器处理极小的值时,我遇到极慢的执行时间问题.为了找到问题,我写了这个测试代码.
通常,循环将在大约200毫秒左右运行.(我没有测量它.)但是当TestCheckBox-> Checked时,它需要大约7秒才能运行.问题在于环路内A,B,C和D的大小减小,这正是IIR滤波器输入变为零后的值所发生的情况.
我认为问题在于变量的指数值小于-308.一个简单的解决方法是将变量声明为long double,但这在实际代码中并不是一个简单的修复,而且我似乎不应该这样做.
任何想法为什么会发生这种情况以及简单的修复可能是什么
如果它很重要,我使用的是C++ Builder XE3.
int j;
double A, B, C, D, E, F, G, H;
//long double A, B, C, D, E, F, G, H; // a fix
A = (double)random(100000000)/10000000.0 - 5.0;
B = (double)random(100000000)/10000000.0 - 5.0;
C = (double)random(100000000)/10000000.0 - 5.0;
D = (double)random(100000000)/10000000.0 - 5.0;
if(TestCheckBox->Checked)
{
A *= 1.0E-300;
B *= 1.0E-300;
C *= 1.0E-300;
D *= 1.0E-300;
}
for(j=0; j<=1000000; j++)
{
A *= 0.9999;
B *= 0.9999;
C …Run Code Online (Sandbox Code Playgroud)