2013-06-17 6 views
5

Ich arbeite in einer Math-Bibliothek, und aufgrund der inhärenten Probleme der Arbeit mit double kodiere ich alle Gleichheitsvergleiche Typ a == b als Math.Abs(a - b) <= epsilon.Wie verwende ich wissenschaftliche Notation in const Feldern?

Auch standardmäßig, möchte ich meine formatierten Strings mit der maximalen Genauigkeit erzeugt werden. Das heißt, wenn Epsilon0.001 ist, möchte ich mein Standardformat N3 sein.

Zum Glück habe ich die folgenden:

public static class Math3D 
{ 
    internal const int ROUND = 3; 
    public const double Epsilon = 1e-ROUND; 
} 

... und ich bekam einen Übersetzungsfehler. Anscheinend ist das nicht erlaubt.

Mit dieser Einschränkung sehe ich keine Möglichkeit, dass ich beide Interdependant-Konstanten als Constants definieren kann. Offensichtlich kann ich Epsilon als ein schreibgeschütztes Feld definieren, aber ich fühle, dass das irgendwie konzeptuell falsch ist. Fehle ich einen offensichtlichen Weg, dies zu tun?

+0

Was ist der wörtliche Fehler? – rae1

+0

Sie machen eigentlich Mathe für'Epsilon' und erzeugen keinen Wert von 0,001. –

+2

Was ist falsch daran, ein 'readonly'-Feld zu verwenden? – xxbbcc

Antwort

10

Wenn Sie es möglicherweise ändern, sollten Sie readonly hier verwenden. const sollte wirklich für Dinge verwendet werden, die nie ändern, wie π. Der Grund dafür liegt in einem feinen Unterschied zwischen const und readonly.

Das Hauptproblem ist, dass, wenn Sie den Wert des const ändern, Sie müssenalle abhängige Clients neu kompilieren, die die const verwenden, sonst kann man shoot yourself in the foot, badly. Also für Werte, die möglicherweise ändern, verwenden Sie nicht const, verwenden Sie readonly.

Also, wenn der Wert nie ändern wird, nur const verwenden und dann mach dir keine Sorgen über Epsilon in Bezug auf ROUND definieren, sagen Sie einfach:

internal const int ROUND = 3; 
public const double Epsilon = 1e-3; 

Wenn Sie wirklich machen wollen Sie sicher, dass Sie versehentlich eine nicht ohne das andere ändern zu ändern, können Sie einen kleinen Check im Konstruktor hinzu:

if (Epsilon != Math.Pow(10, -ROUND)) { 
    throw new YouForgotToChangeBothConstVariablesException(); 
} 

Sie könnten sogar die bedingte Kompilierung hinzufügen so dass nur in Debug-Versionen kompiliert wird.

Wenn es ist ändern wird, verwenden static readonly:

internal readonly int ROUND = 3; 
public static readonly double Epsilon = Math.Pow(10, -ROUND); 

Mit dieser Einschränkung ich keine Möglichkeit sehe ich beide interdependant Konstanten als consts definieren können. [...] Vermisse ich einen offensichtlichen Weg, dies zu tun?

Nein, müssen Sie irgendeine Art von Mathematik zu tun Math.Pow oder Math.Log mit zwischen ROUND und Epsilon zu gehen und die sind nicht akzeptabel für die Kompilierung-Nutzung mit const.Sie könnte schreiben Sie einen Miniatur-Code-Generator, um diese zwei Zeilen Code auf einem einzigen Eingabewert auszuspucken, aber ich frage wirklich den Wert der investierenden Zeit in das.

+0

Der Fehler wird nicht von der 'const' verursacht. – rae1

+0

Nun, genau darum geht es. Beide Störungen werden sich nie ändern und das ist es, was der Code "sagen" soll. In der Entwicklung könnten wir den Wert einige Male fein abstimmen und ich fragte mich nur, ob wir beide irgendwie verketten könnten. Offensichtlich, wenn es keine Lösung gibt, wird der endgültige Code mit zwei unabhängigen Ausfällen geliefert. – InBetween

+0

@InBetween: Sie können nicht die Art von Mathematik zur Kompilierzeit machen, die Sie mit 'const' machen wollen, um das Problem zu lösen, das Sie zu lösen versuchen. – jason

2

1e-ROUND, speziell 1e ist keine gültige literale Ganzzahl. Sie müssten wie etwas tun,

public static readonly double Epsilon = 
    decimal.Parse(
     string.Format("1E-{0}", ROUND), 
     System.Globalization.NumberStyles.Float); 

Auch die static readonly beachten Sie, da Sie kein const, wenn der Ausdruck verwenden können, wird erst zur Laufzeit bekannt sein. Die static readonly funktioniert in diesem Szenario ähnlich wie eine const.

Wenn Sie nicht mit string s tun möchten, können Sie immer tun,

public static readonly double Epsilon = Math.Pow(10, -ROUND); 
+2

... müssen Sie die Zahl in eine Zeichenfolge formatieren und dann analysieren? Nennen Sie mich altmodisch, aber ich finde das einen großen konzeptionellen Umweg. Verwenden Sie eine einfache arithmetische Berechnung, um die Zahl zu erhalten. –

+0

Ich denke nicht, dass dies ein sehr guter Rat ist. Die Verwendung von 'Math.Pow()' wäre in Ordnung und vermeidet eine String-Analyse. – xxbbcc

+0

Ich wollte es so leserlich wie möglich halten. – rae1

1

Sie könnten immer schwer Code nur die 3. wie Sie Konstanten verwenden sehen, dann haben nicht die Absicht, jemals den Wert zu ändern zu etwas anderem als 3 richtig? Sie müssen sich also nicht allzu viele Gedanken über DRY machen.

public static class Math3D 
{ 
    internal const int ROUND = 3; 
    public const double Epsilon = 1e-3; 
} 

Wenn Sie denken, Sie könnten die 3, dann const ist nicht für Sie und Ihre Frage wird strittig ändern möchten.

1

Edit:

Dies ist keine direkte Antwort auf Ihre Frage, aber haben Sie als Round und Epsilon in beschreibbaren Felder zu ändern? Wenn Sie diese zum Formatieren/Runden verwenden, ist es fast garantiert, dass sie sich gelegentlich ändern müssen - weder ein const noch ein readonly Feld funktionieren dafür.

public static class Math3D 
{ 
    internal static int s_Round; 
    internal static double s_Epsilon; 

    static Math3D() 
    { 
     Round = 3; 
    } 

    public static double Epsilon 
    { 
     get 
     { 
      return (s_Epsilon); 
     } 
    } 

    public static int Round 
    { 
     get 
     { 
      return (s_Round); 
     } 
     set 
     { 
      // TODO validate 
      s_Round = value; 
      s_Epsilon = Math.Pow (10, -s_Round); 
     } 
    } 
} 

Es ist eine klar lesbare Lösung, die nicht bricht, wenn Sie Dinge in der Zukunft ändern.

+0

+1 Wenn OP als Arbeiten an einer Math-Bibliothek ist es sinnvoll, das Formatierungsverhalten so anzupassen, dass eine Eigenschaft zum Abrufen und Festlegen der Rundungsgrenze eine gute Idee ist. –

+0

Danke für die Probe. Ich habe im Grunde etwas Ähnliches getan, aber ich sehe wirklich nicht den Grund, warum ich möchte, dass die Verbraucher die * Genauigkeit * der Bibliothek ändern und die Standard "Rundung" kann immer mit Formatzeichenfolgen angepasst werden, so dass dies nicht der Fall ist ein Problem entweder. Die Lösung besteht aus zwei "readonly" -Feldern. – InBetween

+0

@InBetween Ich habe mehrere 3D-Modellierer verwendet, bei denen die Genauigkeit im laufenden Betrieb geändert werden konnte. Dies ist unter bestimmten Umständen sehr nützlich, deshalb habe ich es vorgeschlagen. – xxbbcc

Verwandte Themen