C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
Go Back  Xtreme Visual Basic Talk > > > C++ Weird Floating Point Discrepancies


Reply
 
Thread Tools Display Modes
  #1  
Old 08-27-2017, 06:00 AM
Mathimagics's Avatar
MathimagicsC++ Weird Floating Point Discrepancies Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,159
Question C++ Weird Floating Point Discrepancies


This ones's driving me nuts - I have a C++ library which is heavy on FP computation (it's a kind of physics engine). I build it as a DLL and have a simple API interface (conventional, no class exposure).

The engine produces different results depending on whether the calling app is MSVC or not.

The problem is easily reproduced with a simple program. Just make a DLL (using MSVC or g++, either will do) out of this code (Point.cpp):
Code:
#include <math.h>
#define EXPORT  extern "C" __declspec(dllexport)

namespace Test {

   struct Point {
      double x; 
      double y; 
    
      /* Constructor for a Point object      */
      Point(double xx, double yy) : x(xx), y(yy) {}

      /* Copy constructor                    */
      Point(const Point &rhs) : x(rhs.x), y(rhs.y) {}

      double mag() const;
      Point  norm() const;
      };

   double Point::mag() const {return sqrt(x*x + y*y);}

   Point Point::norm() const {
      double m = mag();
      return Point(x/m, y/m);
      }

   EXPORT void __stdcall GetNorm(double x, double y, double *nx, double *ny) {
      Point P = Point(x, y);
      Point N = P.norm();
      *nx     = N.x;
      *ny     = N.y;
      }
   }
Here is a simple program that calls the DLL, and displays the results:

Code:
#include <stdio.h>

#define IMPORT extern __declspec(dllimport)

IMPORT void __stdcall GetNorm(double x, double y, double *nx, double *ny);

void dhex(double x) {    // double to hex
   union {
       unsigned  long n[2];
       double    d;
       } value;
   value.d = x;
   printf("(0x%0x%0x)\n", value.n[1], value.n[0]);
   }

double i64tod(unsigned long long n) {  // hex to double
   double *DP = (double *) &n;
   return *DP;
   }

int main(int argc, char **argv) {
   double vx, vy;
   double ux, uy;

   vx =  i64tod(0xbfc7a30f3a53d351);
   vy =  i64tod(0xc01b578b34e3ce1d);
   
   GetNorm(vx, vy, &ux, &uy);

   printf("  vx = %20.18f ", vx); dhex(vx);
   printf("  vy = %20.18f ", vy); dhex(vy);
   printf("\n");
   printf("  ux = %20.18f ", ux); dhex(ux);
   printf("  uy = %20.18f ", uy); dhex(uy);
   return 0;
   }
If compiled with MSVC the program produces this result:
Code:
vx =  -0.18466368053455054  (0xbfc7a30f3a53d351)
vy =  -6.8354919685403077   (0xc01b578b34e3ce1d)
ux =  -0.027005566159023012 (0xbf9ba758ddda1454,
uy =  -0.99963528318903927  (0xbfeffd032227301b)
But if caller is GCC (or VB6, or PowerBasic), we get :
Code:
vx = -0.184663680534550540  (0xbfc7a30f3a53d351)
vy = -6.835491968540307700  (0xc01b578b34e3ce1d)
ux = -0.027005566159023008  (0xbf9ba758ddda1453)
uy = -0.999635283189039160  (0xbfeffd032227301a)
The difference is tiny (just the last bit of ux and uy), but over a full physics simulation run these differences add up to objects being in very different positions.

The engine (over 3,000 lines of code) is useless for its intended purpose unless it is deterministic.

The discrepancy above also occurs if the simple DLL above is built with g++, and occurs with different CPU's. There must be rational explanation, but it eludes me!

Any ideas?
__________________
Cogito, ergo codo
Reply With Quote
  #2  
Old 08-27-2017, 06:10 AM
Mathimagics's Avatar
MathimagicsC++ Weird Floating Point Discrepancies Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,159
Default

Here is a VB6/PB version of the calling program:

Code:
Option Explicit

Declare Sub GetNorm Lib "PointG.dll" Alias "GetNorm@24" _
   (ByVal VX As Double, ByVal VY As Double, _
    ByRef UX As Double, ByRef UY As Double)
    
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)

Sub Main()
   Dim VX As Double, VY As Double
   Dim UX As Double, UY As Double
   Dim DP(1) As Long
   Dim msg As String
   DP(1) = &HBFC7A30F: DP(0) = &H3A53D351:   CopyMemory VX, DP(0), 8
   DP(1) = &HC01C578B: DP(0) = &H34E3CE1D:   CopyMemory VY, DP(0), 8
   
   GetNorm VX, VY, UX, UY

   CopyMemory DP(0), UX, 8
   msg = "ux = 0x" & Hex$(DP(1)) & Hex$(DP(0))
   CopyMemory DP(0), UY, 8
   msg = msg & Chr$(10) & "uy = 0x" & Hex$(DP(1)) & Hex$(DP(0))
   MsgBox msg
   End Sub
__________________
Cogito, ergo codo
Reply With Quote
  #3  
Old 08-27-2017, 12:45 PM
Mathimagics's Avatar
MathimagicsC++ Weird Floating Point Discrepancies Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,159
Default

I found the problem - the MSVC dll has no FLDCW instructions, but the calling apps (other than MSVC) all use them, and this apparently changes the rounding mode when the DLL is called.

I took one of the apps, tweaked the EXE to disable the FLDCW instructions, and hey presto, it got the same value as MSVC.
__________________
Cogito, ergo codo
Reply With Quote
Reply

Tags
double, %20.18f, simple, dll, printf, msvc, return, void, engine, hex, extern, vy;, code, #include, constructor, #define, uy;, const;, c++, getnormdouble, g++, program, const, __stdcall, import


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
 
C++ Weird Floating Point Discrepancies
C++ Weird Floating Point Discrepancies
 
-->