none
double precision value varies in an in-process COM dll dependent upon calling program EVEN when input is the same

    Domanda

  • 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


     

    lunedì 12 marzo 2012 23:23

Risposte

  • MyDisplayNameAlex wrote:

    Thanks again for the quick reply.

    Current Control = 786463 from Borland program

    That 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 Pan mercoledì 14 marzo 2012 08:40
    martedì 13 marzo 2012 14:04
  • 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 Pan mercoledì 14 marzo 2012 08:40
    martedì 13 marzo 2012 15:38

Tutte le risposte

  • 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

    lunedì 12 marzo 2012 23:34
  • 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 12:56
  • 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(&currentControl, 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:06
  •  

    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 13:48
  • MyDisplayNameAlex wrote:

    Thanks again for the quick reply.

    Current Control = 786463 from Borland program

    That 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 Pan mercoledì 14 marzo 2012 08:40
    martedì 13 marzo 2012 14:04
  • 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 14:33
  • 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 Pan mercoledì 14 marzo 2012 08:40
    martedì 13 marzo 2012 15:38
  • 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

    martedì 13 marzo 2012 15:42