¿Cómo printf redondea mitades al primer decimal?

11

Estoy probando dos implementaciones diferentes de printfen mi sistema: printf (GNU coreutils) 8.26y la versión incluida zsh 5.3.1. Estoy probando cómo se redondean los medios números, es decir, para 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

Aquí, ambos claramente redondean a la mitad . Sin embargo, cuando pruebo el redondeo al primer decimal, las cosas se vuelven confusas. Es decir, estoy probando 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

Ambas implementaciones lo hacen de manera diferente, y tampoco puedo ver ningún patrón claro. ¿Cómo printfredondean estas dos mitades al primer decimal?

Gavilán
fuente

Respuestas:

19

GNU printf usalong double mientras que zsh usa doubles regular . El comportamiento de redondeo que ve es porque (digamos) 1.45 no puede representarse como una suma de potencias de 2, que es cómo funciona la representación de punto flotante IEEE 754 , y la aproximación más cercana varía según la precisión. Es un poco más (con 80 bits) o menos (con 64 bits), redondeando hacia arriba o hacia abajo como puede ver.

Como siempre, si le interesa la representación y el redondeo precisos a nivel humano, no use coma flotante.

Michael Homer
fuente
1
Solo una nota de que x.25 y x.75 (para x adecuadamente pequeñas) tienen representaciones binarias exactas, a diferencia de las otras.
Toby Speight