Problema na impressão do elemento da matriz no awk

0
p=n/1000
printf "%s",arr[p];

Isso não está imprimindo nada, embora eu tenha verificado o valor de p .
Está saindo bem.
Eu tentei imprimir o elemento desta forma também:

printf "%s",arr[7];

Este aqui funciona.

    
por Rishav 08.09.2018 / 23:09

2 respostas

2

Como mencionado em O Guia do Usuário do GNU Awk 8.2 Usando Números para Matrizes Subscritas

An important aspect to remember about arrays is that array subscripts are always strings. When a numeric value is used as a subscript, it is converted to a string value before being used for subscripting

Se n for 7432 , então n/1000 será 7.432 - não será arredondado por padrão. Então

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = n/1000; print p, arr[p]}'
7.432 foo

enquanto

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = int(n/1000); print p, arr[p]}'
7 seven
    
por 08.09.2018 / 23:32
1

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

    
por 09.09.2018 / 19:18

Tags