2.39. Float’larla çalışma¶
Kayan noktalı sayılar sıradan ondalıklar gibi görünür, ancak davranışlarından birkaçı daha önce bunlarla karşılaşmamış okuyucuları şaşırtır – ve bu davranışlardan biri MicroPython’da masaüstü Python’a kıyasla daha belirgindir. Bu sayfa neler bekleneceğini ve sessizce hatalı davranmayan float kodunun nasıl yazılacağını ele alır.
2.39.1. Hassasiyet¶
Python’un float tipi bir IEEE 754 ikili kayan noktalı sayıdır. Çoğu MicroPython derlemesinde tek hassasiyettir (32 bit); masaüstü CPython ise çift hassasiyet (64 bit) kullanır. Tek hassasiyet yaklaşık yedi ondalık basamak doğruluk taşır; çift hassasiyet yaklaşık on beş taşır.
>>> 0.1 + 0.2
0.3000000
>>> 1.0 / 3.0
0.3333333
>>> 1e30 * 1e30
inf
Temsil edilebilir aralık her iki uçta da daha dardır: büyüklüğü yaklaşık 3.4e38‘den büyük sayılar inf‘e taşar ve yaklaşık 1.2e-38‘den küçük sayılar sıfıra yuvarlanır.
2.39.2. Float’ları karşılaştırma¶
En yaygın tuzak, eşitliği == ile test etmektir:
>>> 0.1 + 0.2 == 0.3
False
Her iki ifade de eşit olmaları gerekiyormuş gibi görünür, ancak 0.1 + 0.2‘nin sonucu, tam olarak 0.3 olmayan en yakın temsil edilebilir değerdir. Bunun yerine bir tolerans kontrolü kullanın – iki float’ın özdeş olup olmadığını değil, yeterince yakın olup olmadığını sorun:
if abs(a - b) < 1e-6:
# close enough
...
Tolerans seçimi değerlerin ölçeğine bağlıdır. Sayılar 1 mertebesinde olduğunda sabit bir 1e-6 iyi çalışır; değerler büyüklük mertebelerine göre değiştiğinde göreceli bir tolerans daha iyidir.
math.isclose() her ikisini de aynı anda ele alır:
from math import isclose
isclose(0.1 + 0.2, 0.3) # True
isclose(1.0e6 + 1, 1.0e6) # True (within default tolerance)
İki anahtar kelime argümanı, hangi tür “yakın”lığın geçerli olacağını kontrol eder:
rel_tol– göreceli tolerans, varsayılan1e-9. İki değer, farkları daha büyük olanın bu kesri içindeyse eşleşir. Herhangi bir ölçekte genel karşılaştırmalar için iyidir.abs_tol– mutlak tolerans, varsayılan0. İki değer, farkları bu sabit miktar içindeyse eşleşir.
math.isclose(), toleranslardan herhangi biri sağlanırsa True döndürür. Varsayılanlar sıfır olmayan sayı çiftlerinin çoğu için uygundur; tuzak, değerlerden birinin tam olarak sıfır olabildiği durumdur. Göreceli tolerans kontrolü “fark ≤ rel_tol × en büyük değer” şeklinde sonuçlanır ve en büyük değer sıfır olduğunda kontrol her zaman başarısız olur:
>>> isclose(0.0, 1e-12)
False
Mutlak tolerans kontrolünde böyle bir sorun yoktur – karşılaştırabileceğiniz değerlerden biri sıfır olduğunda bir abs_tol geçirin:
>>> isclose(0.0, 1e-12, abs_tol=1e-9)
True
2.39.3. Birikim kayması¶
Float’ların uzun toplamları MicroPython’da CPython’dakinden daha hızlı hassasiyet kaybeder, çünkü her ara sonuç tekrar 32 bit hassasiyete yuvarlanır:
total = 0.0
for _ in range(1000000):
total += 0.1
print(total) # noticeably off from 100000.0
Doğruluğun önemli olduğu tekrarlanan toplamalar için iki desen yardımcı olur:
Değerler tam sayılara ölçeklendirilebildiğinde bir tam sayıya biriktirin – saniyeler yerine milisaniyelerle veya voltlar yerine milivoltlarla çalışın, ardından sonda bir kez dönüştürün.
Daha küçük yığınlar halinde hesaplayın ve yığın sonuçlarını toplayın; böylece her toplama benzer büyüklükteki değerler arasında olur.
Tam sayı tarafının böyle bir sınırı yoktur – MicroPython tam sayıları, tıpkı CPython’unkiler gibi, keyfi hassasiyettedir. Seçim hakkınız olduğunda, hassasiyet kaybının birikeceği her şeyde tam sayı aritmetiğini tercih edin.