2017-08-08 3 views
2

Der Titel ist ein bisschen irreführend, weil es nicht genau x und x ist, es ist x und 0,3; jedoch sollten die Werte gleich sein.Warum ist x <= x falsch?

ich habe:

arr = np.arange(0, 1.1, 0.1) 

und ich erhalten:

arr[arr <= 0.3] 
> array([0., 0.1, 0.2]) 

Das richtige Ergebnis sein sollte:

arr[arr <= 0.3] 
> array([0., 0.1, 0.2, 0.3]) 

Ich habe noch nicht auf dieses Problem gestoßen. Ich weiß, dass es mit der Fließkomma-Genauigkeit zusammenhängt ... aber was kann ich hier tun?

+0

Well ... 'arr [arr. Runde (1) <= 0.3] 'funktioniert ... –

+0

Also sollte ich * immer * Zahlen runden, bevor Sie irgendwelche Vergleiche machen? – Xiphias

+1

Äquivalenz zwischen Schwimmern ist immer eine riskante Sache, um zu prüfen. –

Antwort

4

Verlassen Sie sich nicht auf Floats für die Gleichheit zu vergleichen (es sei denn, Sie wissen genau, was Floats Sie beschäftigen). Da kennen Sie die Schrittgröße der Array 0,1 zu erzeugen, verwendet,

arr = np.arange(0, 1.1, 0.1) 

Sie den Schwellenwert erhöhen könnte, 0,3, durch die Halb Schrittgrßenregister eine neue Schwelle zu finden, die sicher zwischen den Werten in arr ist:

In [48]: stepsize = 0.1; arr[arr < 0.3+(stepsize/2)] 
Out[48]: array([ 0. , 0.1, 0.2, 0.3]) 

By the way, die 1.1 in np.arange(0, 1.1, 0.1) ist eine Anwendung der gleichen Idee - angesichts der Launen der Gleitkomma-Arithmetik, konnten wir nicht sicher sein, dass 1.0 in sein würde, Wenn wir np.arange(0, 1.0, 0.1) geschrieben haben, wurde der rechte Endpunkt um die Schrittgröße erhöht.


Grundsätzlich läuft darauf hinaus das Problem auf floating-point arithmetic being inaccurate unten:

In [17]: 0.1+0.2 == 0.3 
Out[17]: False 

So ist der vierte Wert in dem Array ist ein wenig größer als 0,3 ist.

In [40]: arr = np.arange(0,1.1, 0.1) 
In [41]: arr[3] 
Out[41]: 0.30000000000000004 

Beachten Sie, dass Rundung keine gangbare Lösung sein kann. Zum Beispiel wenn arr hat dtype float128:

In [53]: arr = np.arange(0, 1.1, 0.1, dtype='float128') 

In [56]: arr[arr.round(1) <= 0.3] 
Out[56]: array([ 0.0, 0.1, 0.2], dtype=float128) 

Obwohl Herstellung die dtype float128 gemacht arr[3] näher an die dezimalen 0,3,

In [54]: arr[3] 
Out[54]: 0.30000000000000001665 

nun Abrunden nicht produziert eine Zahl kleiner als 0,3:

In [55]: arr.round(1)[3] 
Out[55]: 0.30000000000000000001 
+1

Auch wenn Sie die Schrittgröße nicht kannten, können Sie vielleicht noch etwas tun wie "arr [arr <= 0.3 + sys.float_info.epsilon]" - ich bin jedoch überhaupt nicht zuversichtlich * immer * genug, um den Vergleich zu garantieren ... Was sind deine Gedanken? –

+0

Obwohl - das obige scheint auch auf Ihrem 'float128' Beispiel zu funktionieren ... –

+0

Ich bin nicht sicher, wie man quantifiziert, wie weit die Werte in 'np.arange (...)' von ihren abweichen können idealisierte Dezimalstellen. Abhängig von den Floats ändert sich die Lücke zwischen aufeinanderfolgenden Floats und könnte größer sein als 'sys.float_info.epsilon'. Zum Beispiel: 'x = 10,3; (np.nextafter (x, np.inf) - x)> sys.float_info.epsilon'. – unutbu

1

Unutbu weist auf das Hauptproblem hin. Sie sollten vermeiden, Gleitkommazahlen zu vergleichen, da sie einen Rundungsfehler aufweisen.

Allerdings ist dies ein Problem, auf das viele Menschen stoßen, daher gibt es eine Funktion, die Ihnen hilft, dieses Problem zu umgehen; np.isclose in Ihrem Fall wäre dies führen:

arr[np.logical_or(arr <= 0.3, np.isclose(0.3, arr))] 
>>> array([0., 0.1, 0.2, 0.3]) 

In diesem Fall dies nicht die beste Option sein könnte, aber es könnte hilfreich sein, um diese Funktion zu kennen.

Nebennotiz: Falls Ihnen niemand jemals erklärt hat, warum das passiert. Grundsätzlich speichern Computer alles im Binärformat, jedoch ist 0.1 eine periodische Zahl im Binärformat, dies bedeutet, dass der Computer nicht alle Ziffern speichern kann (da es unendlich viele gibt). Das Äquivalent in dezimal wäre:

1/3 + 1/3 + 1/3 = 0,33333 + 0,33333 + 0,33333 = 0,99999

Welche nicht 1

Verwandte Themen