Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent C# statement for this VB6 operation creating problems

Tags:

I have this code line in VB:

Dim Sqrt As Double Sqrt = Radius ^ 2 - (CenterX - X) ^ 2 

The parameters in the statement above are being passed the values below:

X=  -7.3725025845036161 Double CenterX =0.0            Double Radius= 8.0             Double 

On executing the statement above, the value of Sqrt is below:

Sqrt    9.646205641487505   Double 

Now I wrote a similar C# logic using the Math class:

double Sqrt = 0; Sqrt = Math.Pow(Radius, 2) - Math.Pow((CenterX - X), 2); 

with the same set of values, the output in C# code was:

Sqrt    9.6462056414874979  double 

I need help because of this single change in C# code, all my values are getting affected. Is there anything I can do to get the similar value as of the *VB* source?

like image 890
Apoorv Avatar asked Sep 28 '16 07:09

Apoorv


Video Answer


2 Answers

There is a difference in the precision between the VB6 and the .NET double type. Both are IEEE 64-bit double-precision types, but the .NET CLR uses 80-bit extended-precision internally, i.e. your computations will be more accurate in .NET.

If you have to be backward-compatible with the VB6 precision, you can force your FPU (floating point unit) to use the (less accurate) 64-bit values. This can be achieved using the native _controlfp_s function.

Below is a code snippet that you can use to temporarily "downgrade" floating point precision for backward compatibility. You can use it like this:

Usage

// default floating point precision   using (new FloatingPoint64BitPrecision()) {     // floating-point precision is set to 64 bit }  // floating-point precision is reset to default 

Code Snippet

/// <summary> /// This class changes floating-point precision to 64 bit /// </summary> internal class FloatingPoint64BitPrecision : IDisposable {     private readonly bool _resetRequired;      public FloatingPoint64BitPrecision()     {         int fpFlags;         var errno = SafeNativeMethods._controlfp_s(out fpFlags, 0, 0);         if (errno != 0)         {             throw new Win32Exception(                 errno, "Unable to retrieve floating-point control flag.");         }          if ((fpFlags & SafeNativeMethods._MCW_PC) != SafeNativeMethods._PC_64)         {             Trace.WriteLine("Change floating-point precision to 64 bit");             errno = SafeNativeMethods._controlfp_s(                 out fpFlags, SafeNativeMethods._PC_64, SafeNativeMethods._MCW_PC);              if (errno != 0)             {                 throw new Win32Exception(                     errno, "Unable to change floating-point precision to 64 bit.");             }              _resetRequired = true;         }     }      public void Dispose()     {         if (_resetRequired)         {             Trace.WriteLine("Resetting floating-point precision to default");             SafeNativeMethods._fpreset();         }     } }  internal static class SafeNativeMethods {     [DllImport("msvcr120.dll")]     public static extern void _fpreset();      [DllImport("msvcr120.dll", CallingConvention = CallingConvention.Cdecl)]     public static extern int _controlfp_s(         out int currentControl, int newControl, int mask);      public static int _CW_DEFAULT =          (_RC_NEAR | _PC_53 | _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW          | _EM_UNDERFLOW | _EM_INEXACT | _EM_DENORMAL);      public const int _MCW_EM = 0x0008001f;          // interrupt Exception Masks      public const int _EM_INEXACT = 0x00000001;      //   inexact (precision)      public const int _EM_UNDERFLOW = 0x00000002;    //   underflow      public const int _EM_OVERFLOW = 0x00000004;     //   overflow      public const int _EM_ZERODIVIDE = 0x00000008;   //   zero divide      public const int _EM_INVALID = 0x00000010;      //   invalid      public const int _EM_DENORMAL = 0x00080000;     // denormal exception mask                                                      // (_control87 only)       public const int _MCW_RC = 0x00000300;          // Rounding Control      public const int _RC_NEAR = 0x00000000;         //   near      public const int _RC_DOWN = 0x00000100;         //   down      public const int _RC_UP = 0x00000200;           //   up      public const int _RC_CHOP = 0x00000300;         //   chop       public const int _MCW_PC = 0x00030000;          // Precision Control      public const int _PC_64 = 0x00000000;           //    64 bits      public const int _PC_53 = 0x00010000;           //    53 bits      public const int _PC_24 = 0x00020000;           //    24 bits       public const int _MCW_IC = 0x00040000;          // Infinity Control      public const int _IC_AFFINE = 0x00040000;       //   affine      public const int _IC_PROJECTIVE = 0x00000000;   //   projective  } 
like image 78
Dirk Vollmar Avatar answered Nov 21 '22 19:11

Dirk Vollmar


There no need to use the Math class, simply write your calculus this way :

sqrt = Radius * Radius - (CenterX - x) * (CenterX - x); 
like image 30
romulus001 Avatar answered Nov 21 '22 19:11

romulus001