printf round แบ่งครึ่งเป็นทศนิยมแรกอย่างไร


11

ฉันกำลังทดสอบสองการใช้งานที่แตกต่างกันprintfในระบบของฉัน: และรุ่นที่มาพร้อมกับprintf (GNU coreutils) 8.26 zsh 5.3.1ฉันกำลังทดสอบวิธีการปัดเศษตัวเลขครึ่งหนึ่งเช่น 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

ที่นี่ทั้งสองอย่างชัดเจนครึ่งรอบจะได้ อย่างไรก็ตามเมื่อฉันทดสอบการปัดเศษทศนิยมแรกสิ่งต่าง ๆ จะสับสน นั่นคือฉันกำลังทดสอบ 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

การใช้งานทั้งสองทำได้แตกต่างกันและฉันไม่เห็นรูปแบบที่ชัดเจนในทั้งสอง printfรอบสองเหล่านี้แบ่งเท่า ๆ กันเป็นทศนิยมแรกอย่างไร

คำตอบ:


19

GNU printf ใช้long doubleในขณะที่ zsh ใช้ปกติdouble s พฤติกรรมการปัดเศษที่คุณเห็นนั้นเป็นเพราะ (พูด) 1.45 ไม่สามารถแสดงเป็นผลรวมของพลังของ 2 ซึ่งเป็นวิธีการทำงานของการเป็นตัวแทนจุดลอยตัว IEEE 754และการประมาณที่ใกล้ที่สุดจะแตกต่างกันไปตามความแม่นยำ มันมากขึ้นเล็กน้อย (กับ 80 บิต) หรือน้อยกว่า (กับ 64 บิต) ดังนั้นการปัดเศษขึ้นหรือลงตามที่คุณเห็น

เช่นเคยหากคุณสนใจเกี่ยวกับการเป็นตัวแทนระดับมนุษย์และการปัดเศษที่แม่นยำอย่าใช้เลขทศนิยม


1
เพียงแค่ทราบว่า x.25 และ x.75 (สำหรับ x ขนาดเล็กที่เหมาะสม) มีการเป็นตัวแทนไบนารีที่แน่นอนซึ่งแตกต่างจากคนอื่น ๆ
Toby Speight
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.