como manter n casas decimais? [duplicado]

0

Eu tenho um arquivo com 40.000 linhas

head flower_all

    0.992957746478873 0.00704225352112677
    0.646410833917366 0.353589166082634
    0.992957746478873 0.00704225352112677
    0.992957746478873 0.00704225352112677
    0.992957746478873 0.00704225352112677
    0.992957746478873 0.00704225352112677
    0.992957746478873 0.00704225352112677
    0.992957746478873 0.00704225352112677
    0.5 0.5

Eu quero manter apenas 3 dígitos significativos. Minha saída desejada:

0.992 0.007
0.646 0.353
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.5 0.5

Como posso fazer isso?

    
por Anna1364 21.04.2018 / 20:46

2 respostas

5

com awk :

awk '{ printf("%.3g %.3g\n", $1, $2) }' file

Com os dados fornecidos, isso produz

0.993 0.00704
0.646 0.354
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.5 0.5

Note que 0,00704 tem cinco casas decimais, mas três dígitos significativos.

Se você quiser exatamente três decimais, use %.3f em vez de %.3g e obtenha

0.993 0.007
0.646 0.354
0.993 0.007
0.993 0.007
0.993 0.007
0.993 0.007
0.993 0.007
0.993 0.007
0.500 0.500

As duas variações acima podem ser generalizadas para um número variável de colunas, usando o GNU awk :

awk -v CONVFMT='%.3g' '{ for (i=1; i<=NF; ++i) $i+=0; print }' file

O loop com $i+=0 força awk a reformatar o valor de cada campo como um número de ponto flutuante, o que ele fará levando em conta CONVFMT (ele fará mais ou menos o equivalente a% código%).

Se você quiser cortar os números:

awk '{ for (i=1; i<=NF; ++i) $i=sprintf("%.5s", $i); print }' file

Isto trata os números como strings e os corta depois de cinco caracteres (o que assume que todos os números são menores que 10 e maiores que zero) gerando

0.992 0.007
0.646 0.353
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.5 0.5

Para um corte um pouco mais geral dos números:

awk '{ for (i=1; i<=NF; ++i) if (match($i,".*\.[0-9]?[0-9]?[0-9]?")) $i=substr($i,RSTART,RLENGTH); print }' file

A operação no loop corta os números no ponto em que a correspondência da expressão regular dada termina (se corresponder).

    
por 21.04.2018 / 20:53
1

Seus dados não têm números acima de 1. Eu estendi o arquivo de origem para incluir alguns valores com mais dígitos antes do ponto:

$ cat infile
0.992957746478873 0.00704225352112677
0.646410833917366 0.353589166082634
0.992957746478873 0.00704225352112677
0.5 0.5
16.258137489137 333444.277775666
16.233399999999 333777.277111111

printf

Uma solução possível é usar a função printf compatível com C (o awk tem uma):

o formato f (3 casas decimais (arredondadas))

Uma contagem exata de 3 decimais (arredondados):

$ awk '{ printf("%11.3f %11.3f\n", $1,$2) }' infile
      0.993       0.007
      0.646       0.354
      0.993       0.007
      0.500       0.500
     16.258  333444.278
     16.233  333777.277

Observe que 0.992957746478873 é arredondado para 0.993 .

o formato g (significativo (arredondado))

Uma contagem exata de 3 dígitos (significativos):

$ awk '{ printf("%9.3g %9.3g\n", $1,$2) }' infile
    0.993   0.00704
    0.646     0.354
    0.993   0.00704
      0.5       0.5
     16.3  3.33e+05
     16.2  3.34e+05

Observe o arredondamento no quarto dígito (por exemplo, 3.34e + 05)

String (não arredondada)

Exatamente 3 dígitos (não arredondados) após o ponto decimal.

Usando o GNU awk:

$ gawk '{for(i=1;i<=NF;i++){
         printf( "%12s ",gensub(/([0-9]+\.[0-9]{0,3}).*/, "\1", "g", $i))};print""}
       ' infile
       0.992        0.007
       0.646        0.353
       0.992        0.007
         0.5          0.5
      16.258   333444.277
      16.233   333777.277

Usando sed (provavelmente mais rápido):

$ sed -E 's/([0-9]+\.[0-9]{1,3})[^ ]*//g' infile
0.992 0.007
0.646 0.353
0.992 0.007
0.5 0.5
16.258 333444.277
16.233 333777.277
    
por 22.04.2018 / 00:29