Comment printf arrondit-il la moitié à la première décimale?

11

Je teste deux implémentations différentes de printfsur mon système printf (GNU coreutils) 8.26:, et la version fournie avec zsh 5.3.1. Je teste comment les demi-nombres sont arrondis, c'est-à-dire pour 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

Ici, les deux arrondissent clairement la moitié pour égaliser . Cependant, lorsque je teste l'arrondi à la première décimale, les choses deviennent confuses. Autrement dit, je teste 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

Les deux implémentations le font différemment, et je ne vois aucun modèle clair dans les deux. Comment ces deux printfmoitiés rondes s à la première décimale?

Sparhawk
la source

Réponses:

19

GNU printf utiliselong double alors que zsh utilise des doubles réguliers . Le comportement d'arrondi que vous voyez est dû au fait que (disons) 1,45 ne peut pas être représenté comme une somme de puissances de 2, c'est ainsi que fonctionne la représentation en virgule flottante IEEE 754 , et l'approximation la plus proche varie en fonction de la précision. C'est légèrement plus (avec 80 bits) ou moins (avec 64 bits), arrondissant ainsi vers le haut ou vers le bas comme vous le voyez.

Comme toujours, si vous vous souciez de la représentation et de l'arrondi précis au niveau humain, n'utilisez pas de virgule flottante.

Michael Homer
la source
1
Juste une note que x.25 et x.75 (pour un x convenablement petit) ont des représentations binaires exactes, contrairement aux autres.
Toby Speight