구분된 파일을 읽고 각 레코드에 대해 파일의 세 번째 요소를 추가하는 스크립트가 있습니다. 이 방법은 하나를 제외한 대부분의 데이터 파일에 적합합니다. 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