Paling tidak di Jawa, jika saya menulis kode ini:
float a = 1000.0F;
float b = 0.00004F;
float c = a + b + b;
float d = b + b + a;
boolean e = c == d;
nilai akan . Saya percaya ini disebabkan oleh kenyataan bahwa pelampung sangat terbatas dalam cara merepresentasikan angka secara akurat. Tapi saya tidak mengerti mengapa hanya mengubah posisi dapat menyebabkan ketimpangan ini.
Saya mengurangi s menjadi satu di kedua baris 3 dan 4 seperti di bawah ini, namun nilai menjadi :
float a = 1000.0F;
float b = 0.00004F;
float c = a + b;
float d = b + a;
boolean e = c == d;
Apa yang sebenarnya terjadi pada baris 3 dan 4? Mengapa operasi penambahan dengan pelampung tidak asosiatif?
Terima kasih sebelumnya.
arithmetic
floating-point
numerical-algorithms
Zeta dikenal
sumber
sumber
X
jumlah yang sangat besar dan jumlahY
yang sangat kecil, sedemikian rupaX + Y = X
. Di sini,X + Y + -X
akan menjadi nol. TetapiX + -X + Y
akanY
.Jawaban:
Dalam implementasi floating point tipikal, hasil dari satu operasi dihasilkan seolah-olah operasi dilakukan dengan ketepatan tak terbatas, dan kemudian dibulatkan ke angka floating-point terdekat.
Bandingkan dan b + a : Hasil setiap operasi yang dilakukan dengan ketepatan tak terbatas adalah sama, oleh karena itu hasil ketepatan tak terhingga identik ini dibulatkan dengan cara yang sama. Dengan kata lain, penambahan floating-point bersifat komutatif.a + b b + a
Ambil : b adalah angka floating-point. Dengan angka floating point biner , 2 b juga merupakan angka floating-point (eksponen lebih besar satu), jadi b + b ditambahkan tanpa kesalahan pembulatan. Kemudian sebuah ditambahkan ke tepat nilai b + b . Hasilnya adalah tepat nilai 2 b + a , dibulatkan ke terdekat angka floating-point.b + b + a b 2 b b + b Sebuah b + b 2 b + a
Ambil : a + b ditambahkan, dan akan ada kesalahan pembulatan r , sehingga kami mendapatkan hasil yang + b + r . Menambahkan b , dan hasilnya adalah tepat nilai 2 b + a + r , dibulatkan ke terdekat angka floating-point.a + b + b a + b r a + b + r b 2 b + a + r
Jadi dalam satu kasus, , bulat. Dalam kasus lain, 2 b + a + r , bulat.2 b + a 2 b + a + r
PS. Apakah untuk dua angka tertentu dan b kedua perhitungan memberikan hasil yang sama atau tidak tergantung pada angka, dan pada kesalahan pembulatan dalam perhitungan a + b , dan biasanya sulit diprediksi. Menggunakan presisi tunggal atau ganda tidak membuat perbedaan pada masalah pada prinsipnya, tetapi karena kesalahan pembulatan berbeda, akan ada nilai-nilai a dan b di mana dalam presisi tunggal hasilnya sama dan dalam presisi ganda tidak, atau sebaliknya. Presisi akan jauh lebih tinggi, tetapi masalah bahwa dua ekspresi secara matematis sama tetapi tidak sama dalam aritmatika floating-point tetap sama.Sebuah b a + b
PPS. Dalam beberapa bahasa, aritmatika titik apung dapat dilakukan dengan presisi lebih tinggi atau rentang angka yang lebih tinggi daripada yang diberikan oleh pernyataan aktual. Dalam hal ini, akan jauh lebih mungkin (tetapi masih tidak dijamin) bahwa kedua jumlah memberikan hasil yang sama.
PPPS. Sebuah komentar bertanya apakah kita harus bertanya apakah angka floating point sama atau tidak sama sekali. Tentu saja jika Anda tahu apa yang Anda lakukan. Misalnya, jika Anda mengurutkan array, atau mengimplementasikan set, Anda mendapatkan masalah besar jika Anda ingin menggunakan beberapa gagasan "kira-kira sama". Dalam antarmuka pengguna grafis, Anda mungkin perlu menghitung ulang ukuran objek jika ukuran objek telah berubah - Anda membandingkan oldSize == newSize untuk menghindari perhitungan ulang itu, mengetahui bahwa dalam praktiknya Anda hampir tidak pernah memiliki ukuran yang hampir sama, dan program Anda benar bahkan jika ada perhitungan ulang yang tidak perlu.
sumber
b
dalam jawaban ini bukan 0,00004, itu yang Anda dapatkan setelah konversi dan pembulatan.Format titik mengambang biner yang didukung oleh komputer pada dasarnya mirip dengan notasi ilmiah desimal yang digunakan oleh manusia.
Angka floating-point terdiri dari tanda, mantissa (lebar tetap), dan eksponen (lebar tetap), seperti ini:
Notasi ilmiah reguler memiliki format yang serupa:
Jika kita melakukan aritmatika dalam notasi ilmiah dengan presisi terbatas, pembulatan setelah setiap operasi, maka kita mendapatkan semua efek buruk yang sama dengan binary floating point.
Contoh
Sebagai ilustrasi, misalkan kita menggunakan tepat 3 digit setelah titik desimal.
(a + b) + b
Sekarang kami menghitung:
Pada langkah selanjutnya, tentu saja:
Karenanya (a + b) + b = 9,999 × 10 4 .
(b + b) + a
Tetapi jika kami melakukan operasi dalam urutan yang berbeda:
Selanjutnya kami menghitung:
Karenanya (b + b) + a = 1.000 × 10 5 , yang berbeda dari jawaban kami yang lain.
sumber
Java menggunakan representasi titik mengambang biner IEEE 754, yang mendedikasikan 23 digit biner untuk mantissa, yang dinormalisasi untuk memulai dengan digit signifikan pertama (dihilangkan, untuk menghemat ruang).
Bagian merah adalah mantisa, karena mereka sebenarnya diwakili (sebelum pembulatan).
sumber
Kami baru-baru ini mengalami masalah pembulatan serupa. Jawaban yang disebutkan di atas benar, namun cukup teknis.
Saya menemukan berikut ini menjadi penjelasan yang bagus tentang mengapa kesalahan pembulatan ada. http://csharpindepth.com/Articles/General/FloatingPoint.aspx
TLDR: floating point biner tidak dapat dipetakan secara akurat ke floating point desimal. Ini menyebabkan ketidakakuratan yang dapat bertambah selama operasi matematika.
Contoh menggunakan angka mengambang desimal: 1/3 + 1/3 + 1/3 biasanya akan sama dengan 1. Namun, dalam desimal: 0,333333 + 0,333333 + 0,333333 tidak pernah persis sama dengan 1,000000
Hal yang sama terjadi ketika melakukan operasi matematika pada desimal biner.
sumber