Sua pergunta é "Por que isso acontece?", mas sua pergunta implícita (que outros abordaram) é "Como posso consertar isso?" Você descobriu uma abordagem, que você levantou em um comentário:
So if I multiply it to 1000 to eliminate the point, I can get the exact result, can’t I?
Sim. Bem, 10000, desde que você tenha quatro casas decimais. Considere isto:
awk '{ s+=$1*10000; print $1, s/10000 }'
Infelizmente, isso não funciona, porque a corrupção já ocorreu
assim que interpretamos o token (string) como um número decimal.
Por exemplo, printf "%.20f\n"
mostra que os dados de entrada 0.4157
é realmente interpretado como 0,41570000000000001394.
Neste caso, multiplicando por 10000 você obtém o que você esperaria: 4157.
Mas, por exemplo, 0.5973
= 0,59730000000000005311,
e multiplicando isso por 10000 produz 5973.00000000000090949470.
Então, em vez disso, tentamos
awk '{ s+=int($1*10000); print $1, s/10000 }'
para converter os números que "devem ser" números inteiros (por exemplo, 5973.00000000000090949470)
nos números inteiros correspondentes (5973).
Mas isso falha porque às vezes o erro de conversão é negativo;
por exemplo, 0.7130
é 0,71299999999999996714.
E as funções awk
int(expr)
são truncadas (em direção a zero)
em vez de arredondar, então int(7129.99999999)
é 7129.
Então, quando a vida te dá limões, você faz limonada.
E quando uma ferramenta lhe dá uma função truncada, você adiciona 0.5.
7129.99999999 + 0.5≈7130.49999999 e, claro, int(7130.49999999)
é 7130.
Mas lembre-se: int()
trunca para zero e sua entrada inclui números negativos.
Se pretender arredondar –7129.99999999 para –7130,
você precisa subtrair 0,5 para obter –7130.49999999.
Então,
awk '{ s+=int($1*10000+($1>0?0.5:-0.5)); print $1, s/10000 }'
que adiciona –0,5 a $1*10000
se $1
for ≤ 0.