2016-04-17 5 views
0

Mit Python 2.7.10 habe ich durch Zufall herausgefunden, dass 5 * math.sqrt (3) und math.sqrt (5 ** 2 * 3) nicht die sind gleiche float:Python: seltsames Rundungsverhalten von math.sqrt()

import math 
import decimal 

print decimal.Decimal(5*math.sqrt(3)) 
print decimal.Decimal(math.sqrt(5**2*3)) 
print 5*math.sqrt(3) == math.sqrt(5**2*3) 

kehrt

8.660254037844385521793810767121613025665283203125 
8.6602540378443872981506501673720777034759521484375 
False 

, die zeigt, dass sie am 15. Dezimalstelle abweichen. Faszinierend, diese Zahlen nicht geschieht für benachbarte 5 und 3. Mit dem folgenden Code ein paar Paare von Zahlen zeigen, für welche die Gleichheit nicht:

for j in range(1,10+1): 
    for i in range(1,10+1): 
     a = i*math.sqrt(j) 
     b = math.sqrt(i**2*j) 
     if not(a == b): 
      print [i,j], 

Die Liste der problematischen [i, j] Paare umfassen: [3, 2], [6, 2], [9, 2], [5, 3], [9, 3], [10, 3], [3, 6], [6, 6], [7, 6] , [3, 8], [6, 8], [9, 8], [5, 10], [7, 10], [10, 10] ... Irgendwelche Ideen, warum die Rundung bricht und warum gerade für diese Paare, und nicht andere?

+0

Was erwarten Sie von Decimal? –

+9

Während ein interessanter Fund, nur weil [Fließkomma-Mathematik ist gebrochen] (http://stackoverflow.com/questions/588004/is-floating-point-math-broken). Keiner dieser Werte ist "korrekt" - der Unterschied kann in der Zwischenrundung liegen. – usr2564301

+0

math ist bekannt, dass genaue Ergebnisse mit langen Dezimalzahlen nicht zurückgegeben werden. Ich bezweifle, dass die Liste der "problematischen Paare" ist genau, eher kontextbezogene –

Antwort

1

Dies ist, weil Gleitkommaarithmetik schwierig ist. Keines Ihrer Ergebnisse ist tatsächlich korrekt. Sie haben Rundungsprobleme wegen der Floating-Point und es sieht komisch, weil es nicht auf Potenzen von 10 Runden aber Potenzen von 2

Wenn Sie beliebig genaue Arithmetik benötigen, können Sie das mpmath Modul wie folgt verwenden:

from mpmath import * 

mp.dps=50 
mp.pretty = True 
sqrt3 = fmul(5, mp.sqrt(3)) 
sqrt75 = mp.sqrt(fmul(power(5,2), 3)) 
print "5*sqrt(3) = ", sqrt3 
print "sqrt(5**2*3) = ", sqrt75 

Das gibt:

5*sqrt(3) = 8.6602540378443864676372317075293618347140262690519 
sqrt(5**2*3) = 8.6602540378443864676372317075293618347140262690519 

The link provided by Rad Lexus ist ein gutes Buch zu diesem Thema.

+0

Wenn ich weiter nachforsche, bekomme ich auch unterschiedliche Ergebnisse für 'sqrt (75.0)' in C mit verschiedenen Methoden. 'math.h's native sqrt und' sqrt13' in [dieser erschöpfenden Übersicht] (http://www.codeproject.com/Articles/69941/Best-Square-Root-Method-Algorithm-Function-Precisi) gibt das zweite Python-Ergebnis, während 'sqrt9' es schafft, ** genau ** das erste Python-Ergebnis zu geben - alle 48 Ziffern! Was ist mit diesen Babyloniern, wie? – usr2564301

+0

Die Rundungsprobleme sind nicht nur "wegen des Fließkommas". Die Quadratwurzeln von 3 und 75 sind beide irrational, so dass jede rationale Zahl nur eine Annäherung sein kann. –

+0

@RadLexus "alle 48 Ziffern" berechnete nur die gleiche doppelt genaue Zahl, weil es Berechnungen mit doppelter Genauigkeit verwendete. Das ist kein großer Zufall: Sobald die ersten 17 signifikanten Ziffern gleich waren, mussten auch alle anderen Ziffern gleich sein. –