2016-09-28 2 views
21

I diesen Code Linie in VB haben:Equivalent C# Anweisung für diese VB6 Betrieb zu schaffen Probleme

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

die Parameter in der Anweisung über die Werte unten übergeben werden:

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

die On Ausführung Erklärung oben ist der Wert von Sqrt unter:

Sqrt 9.646205641487505 Double 

Jetzt habe ich WRO te eine ähnliche C# Logik der Math-Klasse:

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

mit dem gleichen Satz von Werten, war der Ausgang in C# Code:

Sqrt 9.6462056414874979 double 

ich wegen dieser einzigen Änderung in C# -Code Hilfe benötigen, Alle meine Werte werden beeinflusst. Gibt es etwas, was ich tun kann, um den gleichen Wert wie der *VB* Quelle zu bekommen?

+4

Ist das VB6 oder VB.NET? Ich bin nicht in der Lage, in VB.NET (.NET 4.5) zu wiederholen, ich bekomme beide Male das gleiche Ergebnis (9.4662056414874979). –

+0

VB6 und teilweise VB.NET – Apoorv

+4

Hier ein paar Hintergrundinformationen zu den verschiedenen Datendarstellungen zwischen vb6 und .net. http://stackoverflow.com/questions/10147436/calling-dll-from-vb6-and-c-sharp-give-slightly-difference-results-in-double-preci – FloatingKiwi

Antwort

5

Es gibt keine Notwendigkeit, die Math-Klasse zu verwenden, einfach Ihr Kalkül auf diese Weise schreiben:

sqrt = Radius * Radius - (CenterX - x) * (CenterX - x); 
+0

dies funktioniert vorerst – Apoorv

+0

Das Problem ist, dass 'CenterX - X' zweimal berechnet wird. Dies wird wahrscheinlich kein Problem sein, da es nur eine einzige Berechnung ist, aber in Fällen, in denen diese Berechnung viel komplizierter ist, könnte es für die Leistung besser sein, diese Berechnung in eine separate Zeile zu extrahieren, so dass es nicht zweimal vorkommt. Auch hier kein Problem, weil die Subtraktion nicht so intensiv ist, aber wenn es etwas Intensives wäre, wäre es besser, es zu trennen. – Nzall

+3

@Nzall: Eigentlich sollte der Compiler den Ausdruck in diesem Fall optimieren können, so dass 'CenterX - X' nur einmal berechnet wird. Dennoch, für etwas viel mehr verworren, steht Ihr Rat immer noch - auch wenn es nur für die Lesbarkeit sein könnte. – hoffmale

32

Es gibt eine difference in the precision between the VB6 and the .NET double type. Beide sind IEEE 64-Bit-Typen mit doppelter Genauigkeit, aber die .NET CLR verwendet interne 80-Bit-Genauigkeit, d. H. Ihre Berechnungen sind in .NET genauer.

Wenn Sie rückwärtskompatibel mit der VB6-Genauigkeit sein müssen, können Sie Ihre FPU (Gleitkommaeinheit) zwingen, die (weniger genauen) 64-Bit-Werte zu verwenden. Dies kann mit der nativen Funktion _controlfp_s erreicht werden.

Im Folgenden finden Sie ein Code-Snippet, mit dem Sie die Fließkomma-Genauigkeit aus Gründen der Abwärtskompatibilität vorübergehend "herabstufen" können. Sie können es wie folgt verwenden:

Nutzungs

// 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 
} 
+0

würde dies überall herabstufen, wo das Double gewesen ist benutzt? – Apoorv

+0

Sie können auch global herunterstufen, indem Sie einfach den Code aus dem 'FloatingPoint64BitPrecision'-Konstruktor in das Startup-Routing Ihrer Anwendung einfügen. –

+0

Muss ich meine Sqrt-Root-Funktion in der using() -Anweisung platzieren? – Apoorv