8

Kare köklere yaklaşmak için bir işlev yazmaya çalışıyordum (matematik modülünün olduğunu biliyorum ... bunu kendim yapmak istiyorum) ve kayan nokta aritmetiği ile berbatlaşıyordum. Bunu nasıl önleyebilirsin?Kayan nokta hataları nasıl önlenir?

>>> sqrt(4) 
2.0000000000000013 
>>> sqrt(9) 
3.00999999999998 

Ben sadece round() kullanabilirsiniz farkındayım ama bu gerçekten doğru yapabilmek istiyorum: Bu kullanma

def sqrt(num): 
    root = 0.0 
    while root * root < num: 
     root += 0.01 
    return root 

bu sonuçları vardır. 6 veya 7 haneye kadar hesaplayabilmek istiyorum. Yuvarlanırsam bu mümkün olmazdı. Python'da kayan nokta hesaplamalarının nasıl düzgün işleneceğini anlamak istiyorum.

+0

Belki deneyin [ondalık] (http://docs.python.org/2/library/decimal.html) modülünün hesaplanması için "Newton yöntemi" aramak hassasiyet için tasarlandı mı? – Michael0x2a

cevap

15

Bu gerçekten Python ile hiçbir ilgisi yoktur - donanımınızın ikili kayan nokta aritmetiğini kullanarak herhangi bir dilde aynı davranışı göreceksiniz. İlk read the docs.

Bunu okuduktan sonra, kodunuza bir yüzlük ekleyerek değil olduğunu anlayacaksınız.

>>> from decimal import Decimal 
>>> Decimal(.01) 
Decimal('0.01000000000000000020816681711721685132943093776702880859375') 

O dize ikili kayan (C "çift hassasiyet") tam ondalık değerini gösterir tahminini kesin ondalık değerine 0,01: Bu eklerken tam olarak ne olduğunu. Gerçekten eklediğiniz şey 1/100'den biraz daha büyük.

Kayan noktalı sayısal hataları denetleme, "sayısal çözümleme" alanıdır ve çok büyük ve karmaşık bir konudur. Şamandıraların yalnızca ondalık değerlere yaklaştırılmasıyla başlamış olmanız koşuluyla, decimal modülünü kullanın. Bu sizin için “sığ” bir dünya sorununu ortadan kaldıracaktır. Sonra

from decimal import Decimal as D 

def sqrt(num): 
    root = D(0) 
    while root * root < num: 
     root += D("0.01") 
    return root 

: Örneğin, işlevine bu küçük değişiklik verilen

>>> sqrt(4) 
Decimal('2.00') 
>>> sqrt(9) 
Decimal('3.00') 

Gerçekten daha doğru değil, ama şimdi tam olarak tek tek ekleyerek çünkü basit örneklerde daha az şaşırtıcı olabilir -yüzüncü.

Alternatif olarak, 'un binary float: I/2**J biçimindeki değerleri tam olarak temsil edilebilir bir şeye eklemek gerekir. Örneğin, 0,01 eklemek yerine, 0.125 (1/8) veya 0,0625 (1/16) ekleyin.

sonra hangi kare kökleri ;-)

+0

Kayıt için dokümanlar okudum ve ben ikili gösterimleri saklamak ile tüm kayan nokta doğruluğu hakkında zaten biliyordum. Newton'un yöntemini unutmuştum. Bütün sorularımı buradan alıyorsun! O zaman keşfettiğin şanslı günüm. Decimal modülünün nasıl çalıştığını merak ediyorum. Kaynağın okunmasının yanı sıra öğrenmenin bir yolu var mı? – Aerovistae

+1

Eh, 'decimal' orijinal olarak Python'da yazılmıştır ve ondalık basamakların listelerinde çalışmıştır (0, 1, 2, ..., 9). Kağıt üzerinde aritmetik yapmayı ne kadar taklit ediyoruz! "Kayan nokta" sadece gösterime bir (ondalık) üssü eklemeyi gerektirir ve çok dikkatli olmak ;-) Geçerli 'ondalık' modülü C olarak kodlanır ve çok daha belirsizdir :-( –

+0

dediğin gibi, denedim ondalık modül kullanarak 4 - 3.2 'çözmek. a = ondalık (4) b = ondalık (3.2) ancak a - b meydana Ondalık olan (',7999999999999998223643160600') – Srinesh