SORU
29 ŞUBAT 2012, ÇARŞAMBA


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
29 ŞUBAT 2012, ÇARŞAMBA


(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:

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

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Creavite

    Creavite

    8 Mart 2009
  • jocc talking shit

    jocc talking

    6 NİSAN 2007
  • New Scientist

    New Scientis

    27 Kasım 2006