Kode berikut jelas salah. Apa masalahnya?
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
r
floating-point
floating-accuracy
r-faq
dplanet
sumber
sumber
Jawaban:
Alasan umum (agnostik bahasa)
Karena tidak semua angka dapat direpresentasikan secara tepat dalam aritmetika titik apung IEEE (standar yang hampir semua komputer gunakan untuk mewakili angka desimal dan berhitung dengan mereka), Anda tidak akan selalu mendapatkan apa yang Anda harapkan. Ini terutama benar karena beberapa nilai yang sederhana, desimal terbatas (seperti 0,1 dan 0,05) tidak terwakili secara tepat di komputer sehingga hasil aritmatika pada mereka mungkin tidak memberikan hasil yang identik dengan representasi langsung dari " diketahui "jawabannya.
Ini adalah batasan aritmatika komputer yang terkenal dan dibahas di beberapa tempat:
Membandingkan skalar
Solusi standar untuk ini
R
adalah bukan menggunakan==
, melainkanall.equal
fungsi. Atau lebih tepatnya, karenaall.equal
memberikan banyak detail tentang perbedaan jika adaisTRUE(all.equal(...))
,.hasil panen
Beberapa contoh lagi menggunakan
all.equal
bukan==
(contoh terakhir seharusnya menunjukkan bahwa ini akan menunjukkan perbedaan dengan benar).Lebih detail, langsung disalin dari jawaban untuk pertanyaan serupa :
Masalah yang Anda temui adalah floating point tidak dapat mewakili pecahan desimal persis di sebagian besar kasus, yang berarti Anda akan sering menemukan bahwa pencocokan tepat gagal.
sementara R terletak sedikit ketika Anda mengatakan:
Anda dapat mengetahui apa yang sebenarnya dipikirkan dalam desimal:
Anda dapat melihat angka-angka ini berbeda, tetapi representasi agak sulit digunakan. Jika kita melihatnya dalam biner (well, hex, yang setara) kita mendapatkan gambaran yang lebih jelas:
Anda dapat melihat bahwa mereka berbeda oleh
2^-53
, yang penting karena angka ini merupakan perbedaan terkecil yang dapat direpresentasikan antara dua angka yang nilainya mendekati 1, seperti ini.Kita dapat mengetahui untuk komputer mana pun berapa angka representable terkecil ini dengan melihat di bidang mesin R :
Anda dapat menggunakan fakta ini untuk membuat fungsi 'hampir sama' yang memeriksa bahwa perbedaannya dekat dengan angka terkecil yang dapat diwakili dalam floating point. Sebenarnya ini sudah ada:
all.equal
.Jadi fungsi all.equal sebenarnya memeriksa bahwa perbedaan antara angka-angka adalah akar kuadrat dari perbedaan terkecil antara dua mantra.
Algoritma ini berjalan agak lucu di dekat angka yang sangat kecil yang disebut denormals, tetapi Anda tidak perlu khawatir tentang itu.
Membandingkan vektor
Diskusi di atas mengasumsikan perbandingan dua nilai tunggal. Dalam R, tidak ada skalar, hanya vektor dan vektorisasi tersirat adalah kekuatan bahasa. Untuk membandingkan nilai elemen vektor, prinsip-prinsip sebelumnya berlaku, tetapi implementasinya sedikit berbeda.
==
adalah vektor (melakukan perbandingan elemen-bijaksana) sambilall.equal
membandingkan seluruh vektor sebagai entitas tunggal.Menggunakan contoh-contoh sebelumnya
==
tidak memberikan hasil "yang diharapkan" danall.equal
tidak melakukan elemen-bijaksanaSebaliknya, versi yang mengulang dua vektor harus digunakan
Jika versi fungsional ini diinginkan, dapat ditulis
yang bisa disebut adil
Atau, alih-alih membungkus
all.equal
lebih banyak panggilan fungsi, Anda bisa meniru internal yang relevanall.equal.numeric
dan menggunakan vektorisasi implisit:Ini adalah pendekatan yang diambil oleh
dplyr::near
, yang mendokumentasikan dirinya sebagaisumber
Menambahkan ke komentar Brian (yang merupakan alasan) Anda dapat mengatasi ini dengan menggunakan
all.equal
sebagai gantinya:Per peringatan Joshua di sini adalah kode yang diperbarui (Terima kasih Joshua):
sumber
all.equal
tidak kembaliFALSE
ketika ada perbedaan, jadi Anda harus membungkusnya denganisTRUE
saat menggunakannya dalamif
pernyataan.Ini retas, tetapi cepat:
sumber
all.equal(... tolerance)
parameter.all.equal(0.147, 0.15, tolerance=0.05)
adalah benar.dplyr::near()
adalah opsi untuk pengujian jika dua vektor angka floating point sama. Ini adalah contoh dari dokumen :Fungsi ini memiliki parameter toleransi bawaan:
tol = .Machine$double.eps^0.5
yang dapat disesuaikan. Parameter default sama dengan default untukall.equal()
.sumber
Saya punya masalah serupa. Saya menggunakan solusi berikut.
output dari interval pemotongan yang tidak sama berdasarkan opsi (digit = 2):
output dari interval pemotongan yang sama berdasarkan fungsi putaran:
sumber
Perbandingan umum ("<=", "> =", "=") dalam aritmatika precion ganda:
Membandingkan a <= b:
Membandingkan a> = b:
Membandingkan a = b:
sumber