2010-11-28 9 views
8

Ich habe ein Problem mit C#. Um genau zu sein mit dem Math.pow(). Wenn ich 15^14 berechnen möchte, bekomme ich "29192926025390624". Aber wenn ich es mit Wolfram Alpha berechne bekomme ich "29192926025390625". Wie Sie sehen können, ist dieser einzige Unterschied 1 Zahl. Wolfram Alpha ist jedoch korrekt. Warum ist C# nicht? und wie kann ich das beheben, damit ich den richtigen Wert in C# bekomme? 7Math.Pow berechnet nicht korrekt

Mein Code ist ziemlich einfach, da ich gerade mit hartcodierten Beispielen versuche. Also was ich mache ist: Math.Pow(15,14); Dies gibt 29192926025390624. Und nicht "29192926025390625", was die richtige Antwort ist.

Links: Wolfram Alpha

+5

Ohne Ihren Code zu sehen, wird alles eine Vermutung sein. Meine Vermutung ist, dass Wolfram Alpha es mit einem Gleitkomma-Typ mit höherer Genauigkeit berechnet. – ChrisF

+4

Übrigens vorausgesetzt, dass 29192926025390625 korrekt ist (es sieht korrekt aus: es endet mit einer "5"), dann verhält sich "Math.Pow" entsprechend der Spezifikation: 29192926025390624 ** ist ** die nächste doppelt genaue IEEE 754-Nummer. Die andere nahegelegene Nummer mit doppelter Genauigkeit ist 29192926025390628. –

+0

Es ist korrekt; Es ist Ihr Verständnis von Fließkomma-Arithmetik und die Spezifikation für "Math.Pow", die fehlerhaft ist. Genießen Sie: http://docs.sun.com/source/806-3568/ncg_goldberg.html – jason

Antwort

9

Math.Pow auf Gleitkommatypen arbeitet, die definitions ungenau. Wenn Sie Ganzzahlen mit beliebiger Genauigkeit benötigen, verwenden Sie einen ganzzahligen Ganzzahltyp, z. B. die BigInteger-Struktur. BigInteger hat auch eine Pow Methode.

+0

Die BigInteger.pow() hat den Trick (ModPow gerade). Vielen Dank. – Ojtwist

+1

@Ojtwist: Nur eine Warnung ... wenn Leistung wirklich wichtig für Sie ist, und dass Operation auf BigInteger eine wirklich große Anzahl von Malen wiederholt wird, sollten Sie denken, Strategie zu ändern (z.Erstellen Sie Ihre eigene Pow-Funktion für Longs zum Beispiel, wie in Yuriy Faktorovichs Antwort vorgeschlagen). – digEmAll

3

Math.Pow funktioniert auf Doppel. Doubles are 64 bit floating point and have about 15-16 digits of precision in C#, und was Sie sehen, ist daher ein Rundungsfehler. So funktionieren Gleitkommazahlen.

Wenn Sie mehr Präzision benötigen, versuchen Sie decimal zu verwenden. Es ist 128 Bits und verwendet 10 als Basis. Dies gibt Ihnen eine genaue Darstellung von Zahlen bis zu 28-29 signifikanten Ziffern. Sie können einfach Ihre eigene Pow-Methode für Dezimalzahlen definieren.

decimal Wenn nicht genug ist, drehen zu BigInteger, die in .NET hinzugefügt wurden 4.

+1

'decimal's sind Gleitkomma als gut, sie verwenden nur Basis 10 statt 2 -> http://csharpindepth.com/Articles/General/Decimal.aspx – digEmAll

+0

@digEmAll, stimmt, das korrigiert. – driis

4

Math.Pow Arbeiten auf Doppelzimmer. Diese Implementierung mit lang wird die richtige Antwort:

Func<long, int, long> power = null; 
power = (i, p) => p == 1 ? i : i*power(i, p - 1); 
Console.WriteLine(power(15, 14)); 
+1

seien Sie vorsichtig mit <1 Potenzen (sieht aus wie ein Stackoverflow für mich: p) (behandeln Sie die 0 Fall sollte genug sein, da mit ints) – Guillaume86

1

Math.Pow() korrekt sein Problems mit doppeltem Datentyp diese Arbeit zu sehen.

 double i = 29192926025390625; 
     Console.WriteLine("{0}",i);//the result will be 29192926025390624.0 

Oops Sorry, Prüfwert von Breakpoint; in deinem Programm;