double precision value varies in an in-process COM dll dependent upon calling program EVEN when input is the same
-
lunedì 12 marzo 2012 23:23
Hi,
I created an in-process COM dll in VC++ 6 and upgraded to now build in VS2010. I call this dll from a VB exe created in VS2008 and rebuilt in VS2010. I also call this dll from a Borland C++ Builder 6 exe. I sometimes get diiferent results from the COM dll even when my input data is identical. I have made a simple example of the problem (below). In the real example, the values used in the calculation of Y are calculated earlier, but the result is the same E VEN IF if I hardwire 'a', 'Rgp', 'b', and 'cth' in the COM dll right before calculating Y. If I run this example from the VB exe, Y= 534.42488136297311. If I run it from the Borland C++ program Y = 534.42488136297300 but if I hover over a - Rgp + b * cth it is 534.42488136297311. It only changes when it is assigned to the Y value.
Since these are doubles, I realized that they are only signficant to 15-16 digits, but why would the value change from 534.42488136297311 to 534.42488136297300 once it is assigned to 'Y' in the Borland Builder exe and not in the VB exe? I feel the value should be 534.42488136297300 because the last 2 digits are not significant with a double. But why the difference when run from the 2 different executables?
double a = 2.0000000000000000;
double Rgp = 0.92202120543430299;
double b = 1.7320508075688772;
double cth = 307.92797776932309;double Y = a - Rgp + b * cth;
Thanks in advance,
Alex
Tutte le risposte
-
lunedì 12 marzo 2012 23:34
On 3/12/2012 7:23 PM, MyDisplayNameAlex wrote:
I created an in-process COM dll in VC++ 6 and upgraded to now build
in VS2010. I call this dll from a VB exe created in VS2008 and
rebuilt in VS2010. I also call this dll from a Borland C++ Builder 6
exe. I sometimes get diiferent results from the COM dll even when my
input data is identical.I bet your results are sensitive to FPU control word - see _controlfp.
Igor Tandetnik
-
martedì 13 marzo 2012 12:56
Hi,
Thanks for your quick response. I tried this using '_controlfp_s' because the help said this was a newer version, but it did not solve the problem. I get the same results. I only have this problem when the COM dll is called from the Borland application. I don't see how the calling program can effect the internals of the COM when I have hard coded the values for the calculation.
THanks,
Alex
A Enterline
-
martedì 13 marzo 2012 13:06
MyDisplayNameAlex wrote:
I don't see how the calling program can effect the internals of the COM when I have hard coded the values for the calculation.
Your floating point calculations are performed by the FPU. The FPU can produce different results while executing the same sequence of machine instructions - they are affected by the rounding mode and such. If you don't explicitly set FPU control word, you are working under whatever settings the host program has configured. This is how results of your calculations may depend on the process your DLL is loaded into.
At the beginning of your method, call
unsigned int currentControl;
_controlfp_s(¤tControl, 0, 0);then print or log the value of currentControl. It would be interesting to compare the values you get from inside the two host processes.
Igor Tandetnik
-
martedì 13 marzo 2012 13:48
Thanks again for the quick reply.
Current Control = 786463 from Borland program
Current Control = 851999 from MS VB
I’m afraid I don’t really know what these “Current Control” values mean. I just want the COM component to give consistent results.
Also, I wrote a consol app in MS using C++ and in Borland C++, not using the COM component and my Y values are:
Y = 534.424881362973 Borland
Y = 534.42488136297311 MS
Even though Borland has many problems in general, I would think that, in this case, Borland is correct because we are only significant to 16 digits correct? The “real” value from the MS calculator program (extended precision) is 534.42488136297302068330839533455 which would round to the Borland value.
Thanks,
Alex
A Enterline
-
martedì 13 marzo 2012 14:04
MyDisplayNameAlex wrote:
Thanks again for the quick reply.
Current Control = 786463 from Borland programThat would be 0xC001F
Current Control = 851999 from MS VB
That would be 0xD001F. The one different bit corresponds to precision control. For Borland it's _PC_64, for VB it's _PC_53. The precision control flag tells whether intermediate results of the calculations should be held on FPU registers as 80-bit floating point values (having 64 bits to represent mantissa), or rounded to 64-bit values (having 53 bits of mantissa).
This would explain why you get more precision while inside a Borland-produced executable, than you do while in VB one.
I�??m afraid I don�??t really know what these �??Current Control�?� values mean.
The documentation for _controlfp[_s] explains the meaning of individual bits.
I just want the COM component to give consistent results.
Then set FPU mask explicitly to a desired value at the beginning of the method (but don't forget to set it back to the original value before returning - the calling process might be sensitive to a particular setting, just as your code is).
Igor Tandetnik
- Contrassegnato come risposta Rob PanModerator mercoledì 14 marzo 2012 08:40
-
martedì 13 marzo 2012 14:33
It works!!! Thank you very much.
I go through this function millions of times. Would it be better if I called '_controlfp_s' from a function higher up? Does it hurt to set the precision at the start of all of my calculations and then reset it at the end or is this a bad idea? (I am doing an optimization so it is an iterative process that may take an hour to finish.)
Thanks,
ALex
A Enterline
-
martedì 13 marzo 2012 15:38
On 3/13/2012 10:33 AM, MyDisplayNameAlex wrote:
I go through this function millions of times. Would it be better if
I called '_controlfp_s' from a function higher up? Does it hurt to
set the precision at the start of all of my calculations and then
reset it at the end or is this a bad idea?You should set it when your COM method is called, and reset it to original value before returning to the code that is not yours. You don't need to set it over and over in every internal function, only on the module boundary.
Igor Tandetnik
- Contrassegnato come risposta Rob PanModerator mercoledì 14 marzo 2012 08:40
-
martedì 13 marzo 2012 15:42
OK.
Thanks again for all of your help. This problem has been driving us crazy for a while. Now it is solved!
Alex
A Enterline

