Bagaimana putaran printf membagi dua ke tempat desimal pertama?


11

Saya menguji dua implementasi berbeda printfpada sistem saya:, printf (GNU coreutils) 8.26dan versi yang dibundel dengan zsh 5.3.1. Saya menguji bagaimana angka setengah dibulatkan, yaitu untuk 1,5, 2,5, 3,5, ... 9,5.

$ for i in {1..9}; do /usr/bin/printf '%.0f\n' "${i}.5"; done
2
2
4
4
6
6
8
8
10
$ for i in {1..9}; do printf '%.0f\n' "${i}.5"; done
2
2
4
4
6
6
8
8
10

Di sini, keduanya jelas setengah bulat sampai genap . Namun, ketika saya menguji pembulatan ke tempat desimal pertama, semuanya menjadi membingungkan. Yaitu, saya menguji 1,15, 1,25, 1,35, ... 1,95.

$ for i in {1..9}; do /usr/bin/printf '%.1f\n' "1.${i}5"; done
1.1
1.2
1.4
1.5
1.5
1.6
1.8
1.9
2.0
$ for i in {1..9}; do printf '%.1f\n' "1.${i}5"; done
1.1
1.2
1.4
1.4
1.6
1.6
1.8
1.9
1.9

Kedua implementasi melakukannya secara berbeda, dan saya juga tidak dapat melihat pola yang jelas. Bagaimana kedua printfputaran ini membagi dua ke tempat desimal pertama?

Jawaban:


19

GNU printf digunakanlong double sementara zsh menggunakan doubles biasa . Perilaku pembulatan yang Anda lihat adalah karena (katakanlah) 1,45 tidak dapat direpresentasikan sebagai jumlah kekuatan 2, yang merupakan cara representasi titik-mengambang IEEE 754 bekerja, dan perkiraan terdekat bervariasi sesuai dengan presisi. Ini sedikit lebih (dengan 80 bit) atau kurang (dengan 64 bit), sehingga membulatkan ke atas atau ke bawah seperti yang Anda lihat.

Seperti biasa, jika Anda peduli dengan representasi dan pembulatan level manusia yang akurat, jangan gunakan floating-point.


1
Hanya sebuah catatan bahwa x.25 dan x.75 (untuk x kecil yang sesuai) memang memiliki representasi biner yang tepat, tidak seperti yang lain.
Toby Speight
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.