Why does this require 20 times more time for these calculations when the values ​​are lowercase


This question already has an answer here:

  • Why does changing 0.1f to 0 slow down performance by 10x? 4 answers

I am a circuit designer, not a software engineer, so I have no idea how to track down this problem.

I am working with some IIR filter code and I am have problems with extremely slow execution times when I process extremely small values through the filter. To find the problem, I wrote this test code.

Normally, the loop will run in about 200 ms or so. (I didn't measure it.) But when TestCheckBox->Checked, it requires about 7 seconds to run. The problem lies with the reduction in size of A, B, C and D within the loop, which is exactly what happens to the values in an IIR filter after it's input goes to zero.

I believe the problem lies with the fact that the variable's expononent value becomes less than -308. A simple fix is to declare the variables as long doubles, but that isn't an easy fix in the actual code, and it doesn't seem like I should have to do this.

Any ideas why this happens and what a simple fix might be?

In case its matters, I am using 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;
  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;

EDIT: As the answers said, the cause of this problem is denormal math, something I had never heard of. Wikipedia has a pretty nice description of it as does the MSDN article given by Sneftel.


Having said this, I still can't get my code to flush denormals. The MSDN article says to do this:

_controlfp(_DN_FLUSH, _MCW_DN)

These definitions are not in the XE3 math libraries however, so I used

controlfp(0x01000000, 0x03000000)

per the article, but this is having no affect in XE3. Nor is the code suggested in the Wikipedia article.

Any suggestions?

You're running into denormal numbers (ones less than DBL_MIN, in which the most significant digit is treated as a zero). Denormals extend the range of the representable floating-point numbers, and are important to maintain certain useful error bounds in FP arithmetic, but operating on them is far slower than operating on normal FP numbers. They also have lower precision. So you should try to keep all your numbers (both intermediate and final quantities) greater than DBL_MIN.

In order to increase performance, you can force denormals to be flushed to zero by calling _controlfp(_DN_FLUSH, _MCW_DN) (or, depending on OS and compiler, a similar function). http://msdn.microsoft.com/en-us/library/e9b52ceh.aspx