2016-08-27 36 views
5

Python 3.5.1'e MATLAB kodu taşıyorum ve bir float yuvarlama sorunu buldum.Python'da yuvarlama/yuvarlama kriterleri

MATLAB, aşağıdaki sayı 6 ondalık basamağa kadar kadar yuvarlanır:

Python
fprintf(1,'%f', -67.6640625); 
-67.664063 

, diğer taraftan, aşağıdaki sayı 6 ondalık basamağa kadar kapalı yuvarlanır:

print('%f' % -67.6640625) 
-67.664062 

İlginçtir ki, sayı '-67,6000625', o zaman bile Python yuvarlanır ise:

print('%f' % -67.6000625) 
-67.600063 

... Bu neden oluyor? Python'da yuvarlama/sonlandırma kriterleri nelerdir? (Bunun, onaltılık değerlerin işlenmesiyle ilgili bir şey olduğuna inanıyorum.)

Daha da önemlisi, bu farkı nasıl önleyebilirim? MATLAB'ın ürettiği çıktıyı tam olarak üretebilen bir python kodu oluşturmam gerekiyor.

+2

Merak ettim ki, bunun davranışını da aynı şekilde araştırdım. Elimdeki tek tuhaftı. np.around (a, 6) '(ilk değerinizle), -67.664062000000001 değerini verir. Denediğiniz ikinci değer: -67.600061999999994. [Resmi python belgeleri] (https://docs.python.org/3/tutorial/floatingpoint.html) bu davranışı açıklar. – Vinay87

+2

Hem C hem de Octave denedim ve hepsi Python ile aynı şekilde -67.664062'yi basıyorlar. – kennytm

+3

Zor float karşılaştırmasının her zaman nasıl olduğu (3.0 * 2.2! = 2.0 * 3.3 gibi) göz önüne alındığında, projenin fizibilitesini sorgulayarak başlayacağım. İki şamandıranı karşılaştırmak için en iyi uygulama, her zaman farkı bazı toleranslarla karşılaştırmaktır. – jadsq

cevap

4

Python davranışının nedeni, kayan nokta sayılarının bir bilgisayarda nasıl saklandığını ve standart numara biçimlerini ve hemen hemen tüm modern bilgisayarlarda kullanılan matematiksel işlemleri tanımlayan IEEE tarafından tanımlanan standartlaştırılmış yuvarlama kurallarıyla ilgilidir.

Numaraları bir bilgisayarda ikili olarak verimli şekilde kaydetme ihtiyacı, önde gelen bilgisayarların kayan nokta sayılarını kullanmasına neden olur. Bu sayılar işlemcilerin çalışabilmesi için kolaydır, ancak birçok ondalık sayının cannot be exactly represented dezavantajına sahiptir. Bu, bazen olması gerektiğini düşündüğümüzden biraz uzakta olmakla sonuçlanır. biz doğrusu onları kesiliyor yerine, Python değerleri genişletmek eğer

durum biraz daha net hale gelir: Gördüğünüz gibi Yani

>>> print('%.20f' % -67.6640625) 
-67.66406250000000000000 
>>> print('%.20f' % -67.6000625) 
-67.60006250000000704858 

, -67.6640625 tam temsil edilebilir bir sayıdır, ama -67.6000625 değil mi' t, aslında biraz daha büyük. Kayan noktalı sayılar için varsayılan yuvarlama modu defined by the IEEE stanard, 5'un yukarısındaki herhangi bir yuvarlamanın yuvarlatılması gerektiğini, aşağıdan yukarıya herhangi bir şeyin aşağı yuvarlanması gerektiğini belirtir. Yani, -67.6000625 durum için, aslında 5 artı küçük bir miktardır, bu yüzden yuvarlanır. Ancak, -67.6640625 söz konusu olduğunda, bu tam olarak beşe eşittir, bu nedenle bir tirebreak kuralı devreye girer. Varsayılan tiebreaker kuralı en yakın çift sayıya yuvarlanır. 2 en yakın etkinlik numarası olduğundan, ikiye yuvarlar.

Python kayan nokta standardı tarafından önerilen yaklaşımı izliyor. Öyleyse, sorun şu ki, MATLAB sürümünüzün bu işlemi yapmıyor. Ben 64bit MATLAB R2016a ile bilgisayarımda denedim ve Python içinde aynı sonucu aldık:

>> fprintf(1,'%f', -67.6640625) 
-67.664062>> 

Yani MATLAB gibi farklı bir yuvarlama yaklaşımı (belki bir standart dışı kullanarak, bir noktada, görünüyor yaklaşım, belki de standartta belirtilen alternatiflerden biri) ve o zamandan beri herkesle aynı kuralları takip etmeye başladı.

+0

Vay, iyi açıkladı. Tamamen ikna oldum. Evet, MATLAB R2011b kullanıyorum, bu yüzden biraz daha büyük. MATLAB'ın her zaman haklı olduğunu düşündüm ama yanılmışım. İyi bir şey, bu konu için Python kodumu düzeltmem gerekmemesidir. ;-) Çok teşekkür ederim! – IanHacker