Script de shell e adição de grandes valores em um problema de arquivo delimitado

2

Eu tenho um script que lê um arquivo delimitado e adiciona o terceiro elemento no arquivo para cada registro. Para a maioria dos arquivos de dados, isso funciona bem, exceto por um. Eu tenho um arquivo de dados onde existem 193 registros no arquivo de dados. Eu estou esperando para obter 2028219.43 de volta do script. Em vez disso, recebo um número exponencial que parece ter sido arredondado. No começo eu pensei que usando o printf eu pegaria o número, mas se o número já tivesse sido arredondado, ele não me devolveria o que estou esperando.

Este é o código que estou usando para ler o arquivo de dados delimitado. Os dados em cada registro são delimitados por um *:

export clm_total=$( awk -F* '{f1+=$3} END {print f1}' datafile.dat)
export new_clm_total=$(printf "%.2f" $clm_total)

Isso é o que aparece no log quando eu executo o script:

+ export clm_total=2.02822e+06
+ printf %.2f 2.02822e+06
+ export new_clm_total=2028220.00
+ echo 2028220.00

Esta é uma amostra do arquivo de dados. Existem mais registros, não achei que fosse necessário exibir todos os 193 registros:

CLM*123456789*4820.9***13:A:1**A*Y*Y
CLM*123698547*3642.05***13:A:7**A*Y*Y
CLM*147852369*579.25***13:A:1**A*Y*Y
CLM*789654123*929.8***13:A:1**A*Y*Y

O que estou esperando de volta é 2028219.43 O que eu estou recebendo é 2.02822e + 06 Que então fica formatado como 2028220.00

    
por Debbie S 15.10.2013 / 18:14

2 respostas

2

Awk realiza aritmética em números de ponto flutuante de precisão dupla. Eu não sei exatamente até que limite você obtém resultados exatos para números com dois decimais, mas você está no alcance. No entanto, este pode ser um problema se os números aumentarem . Se você precisa ter certeza de obter resultados exatos, fique com números inteiros e atente para o estouro, ou use bc que executa aritmética de precisão arbitrária.

O problema aqui é que o awk está computando o resultado correto, mas o formato de impressão padrão é aproximado. Use um formato explícito ao imprimir o resultado.

export clm_total=$( awk -F'*' '{f1+=$3} END {printf "%.2f\n", f1}' datafile.dat)

Como alternativa, você pode ficar com print , desde que altere o formato de impressão para converter números em strings. O padrão é %.6g , o que resulta na aproximação que você está vendo.

export clm_total=$( awk -F'*' -v CONVFMT='%.2f' '{f1+=$3} END {print f1}' datafile.dat)
    
por 16.10.2013 / 02:57
0

Ao lidar com matemática de ponto flutuante na ciência da computação (especificamente awk no seu caso), você deve prestar atenção aos mecanismos subjacentes que estão sendo usados para representar seus dados no sistema.

Eu acredito que este é o problema que você está enfrentando em seu caso particular. Veja este artigo: D.3 Advertências de Número de Ponto Flutuante , para informações adicionais sobre o assunto. Este artigo também foi útil para esclarecer o problema: 15.2 Noções básicas sobre programação de ponto flutuante .

O melhor que posso dizer ao lidar com números de ponto flutuante em awk parece que você tem apenas alguns dígitos disponíveis para a porção mantissa do número, então conforme você continua acumulando números você chega ao ponto em que o arredondamento & erros de truncamento são introduzidos e você está perdendo a precisão.

Exemplo

Você pode ver aqui quando ultrapassamos o limite e começamos a usar a notação científica para rastrear o número real.

$ seq -f "%f" 1413 | awk '{f1+=$1+0.4} END {print f1}'
999556
$ seq -f "%f" 1414 | awk '{f1+=$1+0.4} END {print f1}'
1.00097e+06
    
por 15.10.2013 / 19:01