Neden bu sayılar eşit değil mi?
Aşağıdaki kodu ki yanlış. Sorun nedir?
i <- 0.1
i <- i 0.05
i
## [1] 0.15
if(i==0.15) cat("i equals 0.15") else cat("i does not equal 0.15")
## i does not equal 0.15
CEVAP
(Dil agnostik) genel nedeni
Tüm rakamlar tam olarak IEEE floating point arithmetic (neredeyse tüm bilgisayarlarda ondalık sayıları temsil etmek ve onlarla matematik yapmak için kullandığı standart) temsil edilebilir bu yana, her zaman beklediğin gibi olmaz. Bu özellikle doğrudur çünkü bazı değerleri olan basit, sonlu ondalık (örneğin, 0.1 ve 0.05) temsil ettiği tam olarak bilgisayar ve sonuçlarının aritmetik onları olmayabilir ver sonuç aynı bir doğrudan temsil "bilinen" cevap.
Bu bilgisayar aritmetiği iyi bilinen bir sınırlama var ve çeşitli yerlerde açıklanmıştır:
- Soru var SSS R adamış: R FAQ 7.31
- The R Inferno by Patrick Burns ilk ayırıyor "Daire" bu sorun (Sayfa 9'da başlayarak)
- David Goldberg, Her Bilgisayar Bilimcisi Kayan nokta Hakkında bilmesi gerekenler "Aritmetik"Bilgisayar Anketler ACM23, 1 (1991-03), 5-48 doi>10.1145/103162.103163 (revision also available)
- The Floating-Point Guide - What Every Programmer Should Know About Floating-Point Arithmetic
- Birkaç sorudan oluşan Yığın Taşması
- Why Are Floating Point Numbers Inaccurate?
- Why can't decimal numbers be represented exactly in binary?
- Is floating point math broken?
- 50* *(bu sorun için standart bir cevap hakkında meta bir tartışma)
Skaler karşılaştırılması
R
bu standart çözüm ==
ziyade all.equal
bu fonksiyonu kullanmak için değil. Ya da daha doğrusu, all.equal
beri varsa Eğer, isTRUE(all.equal(...))
farklar hakkında detay sunuyor.
if(isTRUE(all.equal(i,0.15))) cat("i equals 0.15") else cat("i does not equal 0.15")
verir
i equals 0.15
all.equal
kullanarak daha fazla örnek yerine ==
(son örnek, bu doğru farklılıklar gösterir göstermek gerekiyordu).
> 0.1 0.05==0.15
[1] FALSE
> isTRUE(all.equal(0.1 0.05, 0.15))
[1] TRUE
> 1-0.1-0.1-0.1==0.7
[1] FALSE
> isTRUE(all.equal(1-0.1-0.1-0.1, 0.7))
[1] TRUE
> 0.3/0.1 == 3
[1] FALSE
> isTRUE(all.equal(0.3/0.1, 3))
[1] TRUE
> 0.1 0.1==0.15
[1] FALSE
> isTRUE(all.equal(0.1 0.1, 0.15))
[1] FALSE
Detay, doğrudan answer to a similar question kopyalanır: biraz daha fazla
Karşılaştığınız sorun noktası olamaz kayan sık kesin başarısız eşleşen bulacaksınız demektir tam olarak çoğu durumda ondalık kesirler temsil eder.
R derken biraz yatıyor:
> 1.1-0.2
[1] 0.9
> 0.9
[1] 0.9
Gerçekten ondalık ne düşündüğünü öğrenebilirsiniz:
> sprintf("%.54f",1.1-0.2)
[1] "0.900000000000000133226762955018784850835800170898437500"
> sprintf("%.54f",0.9)
[1] "0.900000000000000022204460492503130808472633361816406250"
Bu rakamların farklı olduğunu görebilirsiniz, ama temsili biraz hantal. Eğer ikili (iyi, eşdeğeri olan hex,) onlara bakarsak daha net bir resim elde ederiz
> sprintf("%a",0.9)
[1] "0x1.ccccccccccccdp-1"
> sprintf("%a",1.1-0.2)
[1] "0x1.ccccccccccccep-1"
> sprintf("%a",1.1-0.2-0.9)
[1] "0x1p-53"
Bu sayı 1'e yakın olan iki sayı arasında temsil edilebilir en küçük fark olduğu için önemli olan 2^-53
ile farklı olduğunu görebilirsiniz.
Bu temsil edilebilir en küçük sayı R machine alanında bakarak herhangi bir bilgisayar için bulabiliriz:
> ?.Machine
....
double.eps the smallest positive floating-point number x
such that 1 x != 1. It equals base^ulp.digits if either
base is 2 or rounding is 0; otherwise, it is
(base^ulp.digits) / 2. Normally 2.220446e-16.
....
> .Machine$double.eps
[1] 2.220446e-16
> sprintf("%a",.Machine$double.eps)
[1] "0x1p-52"
Bir 'eşittir' fark kayan nokta olarak temsil edilebilir en küçük sayı bulunur bunu kontrol eden fonksiyon. neredeyse oluşturmak için bu gerçeği kullanabilirsiniz Bu zaten var aslında: all.equal
.
> ?all.equal
....
all.equal(x,y) is a utility to compare R objects x and y testing ‘near equality’.
....
all.equal(target, current,
tolerance = .Machine$double.eps ^ 0.5,
scale = NULL, check.attributes = TRUE, ...)
....
Yani bütün herkes.eşit işlev aslında sayılar arasındaki fark iki mantissas arasında en küçük fark kare kökü olduğunu kontrol ediyor.
Bu algoritma biraz çok az sayıda denormals civarında komik gider, ama bu konuda endişelenmenize gerek yok.
Vektörler karşılaştırılması
Yukarıdaki tartışma İki tek kişilik değerleri karşılaştırması üstlendi. R, skaler yok, vektörler ve örtülü vektörleştirme dil bir güçtür. Vektörler değerini karşılaştırmak için element-wise, önceki ilkelerine tutun, ama uygulama biraz farklı. ==
all.equal
tek bir varlık olarak bütün vektörler karşılaştırır süre vectorized element-bilge bir karşılaştırma yapar.
Önceki örnekler kullanarak
a <- c(0.1 0.05, 1-0.1-0.1-0.1, 0.3/0.1, 0.1 0.1)
b <- c(0.15, 0.7, 3, 0.15)
==
"" sonuç ve all.equal
gerçekleştirmez element-bilge . beklenen vermez
> a==b
[1] FALSE FALSE FALSE FALSE
> all.equal(a,b)
[1] "Mean relative difference: 0.01234568"
> isTRUE(all.equal(a,b))
[1] FALSE
Daha doğrusu, iki vektör üzerinden döngüler bir sürümü kullanılmalıdır
> mapply(function(x, y) {isTRUE(all.equal(x, y))}, a, b)
[1] TRUE TRUE TRUE FALSE
Eğer bu işlevsel bir sürümünü isterseniz, yazılabilir
elementwise.all.equal <- Vectorize(function(x, y) {isTRUE(all.equal(x, y))})
olarak adlandırılan olabilir
> elementwise.all.equal(a, b)
[1] TRUE TRUE TRUE FALSE
Neden't bir yapı her üyenin boyut...
Neden çift.NaN kendisi için eşit değil...
Neden JavaScript iki farklı sayılar eş...
Neden't GCC*****a (**)*(**) optim...
Neden' ◎ܫ◎ ve fonksiyonu t JavaSc...