Why do these calculations take 20 times as long as the values ​​get tiny

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

I am working with some IIR filter code, and I am having problems with extremely slow runtimes when I process very small values ​​through a filter. To find the problem, I wrote this test code.

Typically, the cycle will work after about 200 ms or so. (I did not measure it.) But when TestCheckBox-> Checked, it takes about 7 seconds to start. The problem is reducing the size of A, B, C, and D in the loop, which is exactly what happens with the values ​​in the IIR filter after the input signal reaches zero.

I believe that the problem lies in the fact that the value of the exponential variable becomes less than -308. A simple fix is ​​to declare the variables as doubles, but this is not a simple fix in the actual code, and it seems like I should not do this.

Any ideas why this is happening and what could be a simple fix?

In case of his questions, I use 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; } 

EDIT: As the answers say, the cause of this problem is denormal math, which I have never heard of. Wikipedia has a pretty nice description, as does the MSDN article provided by Sneftel.

http://en.wikipedia.org/wiki/Denormal_number

Having said that, I still can't get my code to reset the denormals. The MSDN article says:

 _controlfp(_DN_FLUSH, _MCW_DN) 

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

 controlfp(0x01000000, 0x03000000) 

in the article, but this does not affect XE3. The code is also not listed in the Wikipedia article.

Any suggestions?

+5
source share
2 answers

You use denormal numbers (units less than DBL_MIN , in which the most significant digit is treated as zero). Denormals expand the range of represented floating point numbers and are important for maintaining certain allowable error limits in FP arithmetic, but working on them is much slower than working on normal FP numbers. They also have lower accuracy. Therefore, you should try to keep all of your numbers (both intermediate and final) larger than DBL_MIN.

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

+11
source

You entered the lower-level floating point area, which led to denormalized numbers - depending on the hardware you are likely to lure into software, which will be much slower than the hardware operations.

+4
source

Source: https://habr.com/ru/post/1205962/


All Articles