2009-07-15 9 views
57

diese Zeilen in C#Dezimalgenauigkeit Anpassen, .net

decimal a = 2m; 
decimal b = 2.0m; 
decimal c = 2.00000000m; 
decimal d = 2.000000000000000000000000000m; 

Console.WriteLine(a); 
Console.WriteLine(b); 
Console.WriteLine(c); 
Console.WriteLine(d); 

diese Ausgabe erzeugt:

2 
2.0 
2.00000000 
2.000000000000000000000000000 

So kann ich sehen, dass eine Dezimalzahl Variable von einer wörtlichen Erstellung ermöglicht es mir, um die Genauigkeit zu steuern.

  • Kann ich die Genauigkeit von Dezimalvariablen anpassen, ohne Literale zu verwenden?
  • Wie kann ich b aus einem erstellen? Wie kann ich b aus c erstellen?

Antwort

44

Das Einbehalten von Nullen wie dieser wurde in .NET 1.1 eingeführt, um eine strengere Übereinstimmung mit der ECMA CLI-Spezifikation zu erreichen.

Es gibt einige Informationen hierzu auf MSDN, z. here.

können Sie die Präzision wie folgt anpassen:

  • Math.Round (oder Decke, Boden etc.) Genauigkeit zu verringern (b von c)

  • Multipliziert mit 1.000 ... (mit die Anzahl der gewünschten Dezimalstellen), um die Genauigkeit zu erhöhen - z multipliziere mit 1,0M, um b von a zu erhalten.

+5

Auch _divide_ von '1.000 ...', um die Genauigkeit zu verringern. –

17

Sie sehen nur verschiedene Darstellungen der exakt gleichen Daten. Die Genauigkeit einer decimal wird so skaliert, dass sie so groß ist, wie sie sein muss (im Rahmen des Zumutbaren).

Von System.Decimal:

eine Dezimalzahl ist eine Gleitkommazahl Wert, der aus einem Zeichen besteht, ein numerischer Wert, bei dem jede Ziffer in dem Wert von 0 bis 9 reicht und a Skalierungsfaktor, der die Position eines gleitenden Dezimalpunkts angibt, der das Integral und Bruchteile des numerischen Werts trennt.

Die binäre Darstellung eines Decimal Wert besteht aus einem 1-Bit-Zeichen, eine 96-Bit-Integer-Zahl, und ein Skalierungs Faktor verwendet, um die 96-Bit- ganze Zahl zu teilen und spezifizieren, welchen Teil es ist ein Dezimalbruch. Der Skalierungsfaktor ist implizit die Zahl 10, zu einem Exponenten von 0 bis 28. Daher hin angehoben, die binäre Darstellung eines Dezimalwert der Form, ((-2 -2 )/10 (0 bis 28)), wobei -2 96 -1 bis MinValue gleich ist, und 2 -1 ist MaxValue gleich.

Der Skalierungsfaktor behält auch abschließende Nullen in einer Dezimalzahl bei. Nachlaufende Nullen beeinflussen nicht den Wert einer Dezimalzahl in arithmetischen oder Vergleichsoperationen. Nachgestellte Nullen können jedoch von der ToString-Methode aufgedeckt werden, wenn eine entsprechende Formatzeichenfolge angewendet wird.

+1

Gute Informationen über Skalierungsfaktor ... wie kann ich es jetzt anpassen? –

+1

Der Skalierungsfaktor ist nicht direkt steuerbar, da er sich basierend auf der Größe des Exponenten einstellt. Dies ist im Grunde, wie Gleitkomma funktioniert (und wo der Begriff "Floating" herkommt). Da die Anzahl der Bits im Signifikanden konstant ist, bestimmt die Größe der Zahl den Maßstab der signifikanten Bits. – codekaizen

+0

Es wird automatisch an die Daten angepasst, die es enthält. Gibt es einen besonderen Grund, warum Sie es manuell skalieren müssen? –

1

Die Frage ist - brauchen Sie wirklich die Genauigkeit gespeichert in der Dezimalstelle, anstatt nur die Dezimalstelle mit der erforderlichen Genauigkeit anzuzeigen. Die meisten Anwendungen wissen intern, wie genau sie genau sein wollen und anzeigen. Zum Beispiel, selbst wenn ein Benutzer eine Rechnung für 100 in einem Konto-Paket eingibt, druckt es immer noch als 100.00 mit etwas wie val.ToString ("n2").

Wie kann ich b aus einem erstellen? Wie kann ich b aus c erstellen?

c bis b ist möglich.

Console.WriteLine(Math.Round(2.00000000m, 1)) 

produziert 2.0

a zu b ist heikel, wie der Begriff Präzision der Einführung einer kleinen fremd Mathematik.

Ich denke, ein schrecklicher Hack könnte eine Rundreise sein.

decimal b = Decimal.Parse(a.ToString("#.0")); 
Console.WriteLine(b); 

produziert 2.0

5

Ich fand, dass ich mit der Skala durch Multiplizieren oder Dividieren von einem ausgefallenen 1.

decimal a = 2m; 
decimal c = 2.00000000m; 
decimal PreciseOne = 1.000000000000000000000000000000m; 
    //add maximum trailing zeros to a 
decimal x = a * PreciseOne; 
    //remove all trailing zeros from c 
decimal y = c/PreciseOne; 

"tamper" könnte I 1 eine ausreichend präzise herstellen kann Skalierung ändern Faktoren nach bekannten Größen.

+3

Interessant, aber gleichzeitig rätselhaft. Was genau ist der Unterschied zwischen 2.0m und 2.00000000m? In non-computing-Umgebung würde ich damit meinen, dass die letztere Zahl zu dieser Genauigkeit garantiert wurde, während die erstere nur bis zur ersten Dezimalstelle garantiert wurde. Die Multiplikation sollte jedoch bedeuten, dass das Ergebnis nur auf eine Dezimalstelle genau ist. – sgmoore

5

Es ist verlockend, mit decimal in .NET decimal in SQL Server zu verwirren; sie sind ganz anders.

Ein SQL Server decimal ist eine Festkommazahl, deren Genauigkeit und Skalierung festgelegt sind, wenn die Spalte oder Variable definiert wird.

A NET decimal ist eine Gleitkommazahl wie float und double (wobei der Unterschied darin, dass decimal genau Dezimalziffern während float und double genau Binärziffern bewahren bewahrt). Der Versuch, die Genauigkeit eines .NET decimal zu steuern, ist sinnlos, da alle Berechnungen unabhängig vom Vorhandensein oder Fehlen von Füll-Nullen die gleichen Ergebnisse liefern.

+0

Interessanterweise erzeugt das Setzen der Facetten auf eine Dezimalstelle in EF eine richtige 'SQL-Dezimalstelle', die sofort fehlschlägt, wenn eine 'C# Dezimalstelle' übergeben wird ... in meinem Fall verwendete ich Precision: 2, Scale: (none) und ich kann '800' nicht zuweisen, da der Wert außerhalb des Bereichs liegt – ekkis

-1

Dadurch werden alle nachfolgenden Nullen aus dem Dezimaltrennzeichen entfernt und Sie können einfach ToString() verwenden.

public static class DecimalExtensions 
{ 
    public static Decimal Normalize(this Decimal value) 
    { 
     return value/1.000000000000000000000000000000000m; 
    } 
} 

Oder alternativ, wenn Sie eine genaue Anzahl von Nullen wollen, sagen wir 5, erste Normalisieren() und dann multiplizieren mit 1.00000m.

+0

Keine Notwendigkeit für viele Nullen, kann mit 28 Nullen nach der '1' gemacht werden. Siehe Kommentare zu [andere Antwort] (http://stackoverflow.com/a/7983330/1336654). –