c++ - 当值变得很小时,为什么这些计算需要多 20 倍的时间

标签 c++ c++builder x86

<分区>

我是一名电路设计师,不是软件工程师,所以我不知道如何追踪这个问题。

我正在使用一些 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 中没有影响。维基百科文章中建议的代码也不是。

有什么建议吗?

最佳答案

您遇到了非正规数字(小于 DBL_MIN 的数字,其中最高有效数字被视为零)。非正规化扩展了可表示 float 的范围,并且对于在 FP 算术中保持某些有用的错误界限很重要,但对它们进行操作比对普通 FP 数进行操作要慢得多。它们的精度也较低。因此,您应该尽量使所有数字(包括中间数量和最终数量)都大于 DBL_MIN。

为了提高性能,您可以通过调用 _controlfp(_DN_FLUSH, _MCW_DN)(或者,根据操作系统和编译器,调用类似的函数)强制将非正规化刷新为零。 http://msdn.microsoft.com/en-us/library/e9b52ceh.aspx

关于c++ - 当值变得很小时,为什么这些计算需要多 20 倍的时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26676853/

相关文章:

c++ - 标准属性和 GNU "__attribute__"之间有什么区别?

delphi - TInterfacedObject 自动内存管理也可以与 C++Builder 一起使用吗?

delphi - RAD 工作室 2011 (?)

arrays - 将值插入数组并显示,nasm

x86 - Core i7 中每核 L2 和 L3 之间的互连

c++ - CMake的package_find冲突如何解决?

c++ - 插装代码导致无限递归循环

c++ - 为什么 GLUT 如此糟糕?

c++ - 如何升级 c++ builder 2010 boost 库

c - 这个集会怎么可能?