Genel (dil agnostik) nedeni
, her zaman olmaz beklediğin şeyi al. Bu, özellikle doğrudur, çünkü basit, sonlu ondalık değerler (örneğin, 0.1 ve 0.05), bilgisayarda tam olarak gösterilmemektedir ve bu nedenle, üzerinde bulunan aritmetik sonuçları, doğrudan bir temsil ile aynı sonucu vermeyebilir. bilinen "cevap.
Bu
bilgisayar aritmetiği iyi bilinen bir sınırlamadır ve çeşitli yerlerde de tartışılmıştır:
karşılaştırılması skalerler
R
bu standart çözüm ==
kullanmak değil, daha ziyade all.equal
fonksiyonu. Veya daha doğrusu, all.equal
, isTRUE(all.equal(...))
varsa, farklar hakkında birçok ayrıntı verir.
if(isTRUE(all.equal(i,0.15))) cat("i equals 0.15") else cat("i does not equal 0.15")
yerine ==
arasında all.equal
kullanmanın
i equals 0.15
bazı daha fazla örnek verir (son örnekte, bu doğru farklılık gösterecektir göstermek için beklenen).
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
Biraz daha detay, doğrudan answer to a similar question kopyalanan: karşılaşmış
sorun kayan nokta sık o tam eşleme başarısız bulacaksınız demektir tam olarak çoğu durumda ondalık kesirleri temsil edemezler.R hafifçe yatarken
derken:
1.1-0.2
#[1] 0.9
0.9
#[1] 0.9
Sen 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 sayılar farklı, ama temsil edilmemesi olduğunu görebilirsiniz biraz beceriksiz.
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"
Onların bu sayı Temsil edilebilir en küçük bir fark arasındaki çünkü önemli olan, 2^-53
farklılık olduğunu görebilirsiniz: Biz ikili onlara bakacak olursak (iyi, eşdeğerdir onaltılık) biz daha net bir resim elde değeri 1'e yakın olan iki sayı, olduğu gibi.
Biz bu Temsil edilebilir en küçük sayı R'ın machine alanında bakarak ne olduğunu herhangi bir bilgisayar için öğrenebilirsiniz: Sen oluşturmak için bu gerçeği kullanabilirsiniz
?.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 fark olduğunu denetler işlevi 'neredeyse eşittir' kayan noktadaki en küçük temsil edilebilir sayıya yakındır. Aslında bu zaten mevcut: 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 all.equal fonksiyonu aslında sayılar arasındaki farkın iki mantislerdeki arasındaki en küçük farkın karekökü olduğunu kontrol ediyor.
Bu algoritma, denormals adı verilen son derece küçük sayılara yakın biraz eğlenceli olur, ancak bunun için endişelenmenize gerek yoktur.
karşılaştırılması vektörleri
Yukarıdaki tartışma, iki tek değerlerinin karşılaştırılması üstlendi. R'de skaler yoktur, sadece vektörler ve örtük vektörler dilin bir gücüdür. Vektörel elemanların değerini karşılaştırmak için, önceki ilkeler geçerlidir, ancak uygulama biraz farklıdır. ==
vektörleştirilmiştir (bir eleman-karşılaştırma karşılaştırması) iken all.equal
tüm vektörleri tek bir varlık olarak karşılaştırmaktadır.
kullanarak önceki örnekler
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)
==
, öğeye göre yerine
a==b
#[1] FALSE FALSE FALSE FALSE
all.equal(a,b)
#[1] "Mean relative difference: 0."
isTRUE(all.equal(a,b))
#[1] FALSE
iki vektörün üzerinde döngüler bir sürüm gerçekleştirmez "beklenen" sonucu ve all.equal
vermez gerekir
mapply(function(x, y) {isTRUE(all.equal(x, y))}, a, b)
#[1] TRUE TRUE TRUE FALSE
İşlevsel Bu sürümü sadece ilgili iç görün çoğaltabilir, bunun yerine daha da işlev çağrıları all.equal
sarma, Alternatif sadece
elementwise.all.equal(a, b)
#[1] TRUE TRUE TRUE FALSE
olarak çağrılabilir
elementwise.all.equal <- Vectorize(function(x, y) {isTRUE(all.equal(x, y))})
yazılabilir, istendiği
all.equal.numeric
ve örtük vektörelleştirmeyi kullanın: Eğer üzerinde bizim tarafımızdan bu gelebilir (sebebidir) Brian'ın yorumuna ekleme
tolerance = .Machine$double.eps^0.5
# this is the default tolerance used in all.equal,
# but you can pick a different tolerance to match your needs
abs(a - b) < tolerance
#[1] TRUE TRUE TRUE FALSE
Ayrıca bkz: http: //stackoverflow.com/q/6874867 ve http://stackoverflow.com/q/2769510. [R Inferno] (http://www.burns-stat.com/pages/Tutor/R_inferno.pdf) ayrıca bir başka harika okumadır. – Aaron