Um complemento para a @resposta fina do steeldriver .
7432/1000 não é um inteiro. awk
internamente usa o tipo double
do compilador C para representar números de ponto flutuante. Nos sistemas GNU no x86, esse é o binário64 do IEEE 754.
Assim como 1/3 não pode ser representado em decimal (que é 0.33333 com um número infinito de 3s), 7432/1000 não pode ser representado em binário. awk
' double
aproximação desse número é um número binário que quando convertido de volta para decimal é (exatamente) 7.4320000000000003836930773104541003704071044921875.
Agora, em awk
, quando números não inteiros são convertidos em uma representação de string, o valor exato da representação interna binária não é totalmente preservado. Isso não seria muito útil, pois, de qualquer maneira, a maioria desses dígitos acima representa um erro. Em vez disso, os números de ponto flutuante são convertidos de volta para string usando o parâmetro CONVFMT
special, que contém um formato printf
-like¹
Por padrão, CONVFMT
é %.6g
. O que significa que apenas 6 dígitos decimais de precisão são retidos na conversão para string. Isso pode ser alterado para qualquer coisa, mas observe que apenas especificadores de ponto flutuante ( %e
, %f
, %g
...) são portáveis.
Esses números são convertidos em string quando são usados como argumento para funções ou operadores que esperam sequências, como substr()
, concatenação ...
Um desses, como @steeldriver, disse que são chaves para matrizes associativas que são sempre strings.
Portanto, a[7432/1000] = x
está realmente fazendo a[sprintf(CONVFMT, 7432/1000)]
. Com o valor padrão de CONVFMT
, isso se torna a["0.7432"] = x
, mas se CONVFMT
foi alterado para %.1e
, isso seria a["7.0e-01"] = x
ou, se fosse %.25g
, seria a["7.4320000000000003837"] = x
.
Então, aqui você pode usar CONVFMT=%.0f
para garantir que as chaves da matriz sejam inteiros:
$ awk -v CONVFMT=%.0f 'BEGIN{a[7432/1000] = 1; print a[7]}'
1
No entanto, observe que %.0f
arredonda para o inteiro mais próximo, enquanto %d
trunca a parte decimal. O uso de CONVFMT=%d
não é portátil, embora funcione com gawk
e mawk
:
$ gawk -v CONVFMT=%d 'BEGIN{a[7564/1000] = 1; print a[7]}'
1
$ gawk -v CONVFMT=%.0f 'BEGIN{a[7564/1000] = 1; print a[8]}'
1
¹ que não cobre argumentos de ponto flutuante para print
, que são convertidos usando OFMT
em vez