Wie werden runde Hälften auf die erste Dezimalstelle gedruckt?

11

Ich teste zwei verschiedene Implementierungen printfauf meinem System: printf (GNU coreutils) 8.26und die mitgelieferte Version zsh 5.3.1. Ich teste, wie halbe Zahlen gerundet werden, dh für 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

Hier runden beide deutlich die Hälfte bis gerade ab . Wenn ich jedoch das Runden auf die erste Dezimalstelle teste, werden die Dinge verwirrend. Das heißt, ich teste auf 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

Beide Implementierungen machen es unterschiedlich, und ich kann auch kein klares Muster erkennen. Wie gehen diese beiden printfrunden Hälften auf die erste Dezimalstelle?

Sparhawk
quelle

Antworten:

19

GNU printf verwendet,long double während zsh reguläres doubles verwendet . Das Rundungsverhalten, das Sie sehen, ist, weil (sagen wir) 1,45 nicht als Summe von Potenzen von 2 dargestellt werden kann. So funktioniert die Gleitkomma-Darstellung nach IEEE 754 , und die nächste Näherung variiert je nach Genauigkeit. Es ist etwas mehr (mit 80 Bit) oder weniger (mit 64 Bit) und rundet also auf oder ab, wie Sie sehen.

Verwenden Sie nach wie vor kein Gleitkomma, wenn Sie sich für eine genaue Darstellung und Rundung auf menschlicher Ebene interessieren.

Michael Homer
quelle
1
Nur eine Anmerkung, dass x.25 und x.75 (für entsprechend kleine x) im Gegensatz zu den anderen exakte binäre Darstellungen haben.
Toby Speight