<分区>
我是一名电路设计师,不是软件工程师,所以我不知道如何追踪这个问题。
我正在使用一些 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 *= 0.9999;
D *= 0.9999;
E = A * B + C - D; // some exercise code
F = A - C * B + D;
G = A + B + C + D;
H = A * C - B + G;
E = A * B + C - D;
F = A - C * B + D;
G = A + B + C + D;
H = A * C - B + G;
E = A * B + C - D;
F = A - C * B + D;
G = A + B + C + D;
H = A * C - B + G;
}
编辑: 正如答案所说,这个问题的原因是非正规数学,这是我从未听说过的。维基百科和 Sneftel 提供的 MSDN 文章一样对其进行了很好的描述。
http://en.wikipedia.org/wiki/Denormal_number
话虽如此,我仍然无法让我的代码刷新非正规化。 MSDN 文章说要这样做:
_controlfp(_DN_FLUSH, _MCW_DN)
但是这些定义不在 XE3 数学库中,所以我使用了
controlfp(0x01000000, 0x03000000)
根据文章,但这在 XE3 中没有影响。维基百科文章中建议的代码也不是。
有什么建议吗?