
구분된 파일을 읽고 각 레코드에 대해 파일의 세 번째 요소를 추가하는 스크립트가 있습니다. 대부분의 데이터 파일의 경우 하나만 제외하고는 잘 작동합니다. 데이터 파일에 193개의 레코드가 있는 데이터 파일이 하나 있습니다. 스크립트에서 2028219.43을 다시 얻을 것으로 예상됩니다. 대신, 반올림된 것처럼 보이는 지수 숫자를 다시 얻습니다. 처음에 나는 printf를 사용하면 숫자를 얻을 수 있다고 생각했지만 숫자가 이미 반올림된 경우에는 내가 기대했던 것을 돌려주지 못할 것입니다.
이것은 구분된 데이터 파일을 읽는 데 사용하는 코드입니다. 각 레코드의 데이터는 *로 구분됩니다.:
export clm_total=$( awk -F* '{f1+=$3} END {print f1}' datafile.dat)
export new_clm_total=$(printf "%.2f" $clm_total)
스크립트를 실행할 때 로그에 나타나는 내용은 다음과 같습니다.
+ export clm_total=2.02822e+06
+ printf %.2f 2.02822e+06
+ export new_clm_total=2028220.00
+ echo 2028220.00
데이터 파일의 샘플입니다. 더 많은 레코드가 있지만 193개의 레코드를 모두 표시할 필요는 없다고 생각했습니다.
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
내가 돌려받을 것으로 예상하는 것은 2028219.43입니다. 내가 돌려받는 것은 2.02822e+06입니다. 그런 다음 2028220.00 형식으로 지정됩니다.
답변1
Awk는 배정밀도 부동 소수점 숫자에 대한 산술을 수행합니다. 소수점 이하 두 자리가 있는 숫자에 대해 정확한 결과를 얻을 수 있는 한계가 어느 정도인지는 정확히 알 수 없지만 범위 내에 있습니다. 그러나 이것은숫자가 커지면 문제가 될 수 있습니다.. 정확한 결과를 얻으려면 정수를 사용하고 오버플로를 주의하거나 bc
임의 정밀도 산술을 수행하는 기능을 사용하세요.
여기서 문제는 awk가 올바른 결과를 계산하지만 기본 인쇄 형식은 근사치라는 것입니다. 결과를 인쇄할 때 명시적인 형식을 사용하십시오.
export clm_total=$( awk -F'*' '{f1+=$3} END {printf "%.2f\n", f1}' datafile.dat)
print
또는 숫자를 문자열로 변환하기 위해 인쇄 형식을 변경하는 경우 계속 사용할 수 있습니다 . 기본값은 %.6g
보고 있는 근사값입니다.
export clm_total=$( awk -F'*' -v CONVFMT='%.2f' '{f1+=$3} END {print f1}' datafile.dat)
답변2
컴퓨터 과학에서 부동 소수점 수학을 다룰 때(특히 awk
귀하의 경우) 시스템 내에서 데이터를 표현하는 데 사용되는 기본 메커니즘에 주의를 기울여야 합니다.
나는 이것이 당신의 특별한 경우에 직면하고 있는 문제라고 생각합니다. 이 문서를 참조하세요:D.3 부동 소수점 수 주의 사항, 해당 주제에 대한 추가 정보를 확인하세요. 이 기사는 문제를 밝히는 데에도 도움이 되었습니다.15.2 부동 소수점 프로그래밍 이해하기.
부동 소수점 숫자를 처리할 때 가장 잘 알 수 있는 점 awk
은 숫자의 가수 부분에 사용할 수 있는 숫자가 몇 개밖에 없는 것으로 나타나므로 숫자를 계속 누적하면 반올림 및 잘림 오류가 발생하는 지점에 도달하게 됩니다. 정확성이 떨어지고 있습니다.
예
임계값을 초과하고 과학적 표기법을 사용하여 실제 숫자를 추적하기 시작하면 여기에서 볼 수 있습니다.
$ 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