Como printf arredonda pela metade para a primeira casa decimal?

11

Estou testando duas implementações diferentes printfno meu sistema: printf (GNU coreutils) 8.26e a versão que acompanha o pacote zsh 5.3.1. Estou testando como os números médios são arredondados, ou seja, 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

Aqui, ambos claramente arredondam metade para o par . No entanto, quando testo o arredondamento para a primeira casa decimal, as coisas ficam confusas. Ou seja, estou testando para 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 as implementações fazem isso de maneira diferente e também não vejo nenhum padrão claro. Como esses dois printfs arredondam pela metade a primeira casa decimal?

Sparhawk
fonte

Respostas:

19

O GNU printf usalong double enquanto o zsh usa doubles regulares . O comportamento de arredondamento que você vê é porque (digamos) 1,45 não pode ser representado como uma soma de potências de 2, que é como a representação em ponto flutuante IEEE 754 funciona e a aproximação mais próxima varia de acordo com a precisão. É um pouco mais (com 80 bits) ou menos (com 64 bits), arredondando para cima ou para baixo como você vê.

Como sempre, se você se preocupa com a representação e o arredondamento precisos no nível humano, não use ponto flutuante.

Michael Homer
fonte
1
Apenas observe que x.25 e x.75 (para x adequadamente pequeno) têm representações binárias exatas, ao contrário das outras.
precisa