BASH에서 "부동 숫자"를 반올림하는 방법을 검색하는 데 몇 시간을 보냈지만 올바른 것을 찾을 수 없습니다! 해결 방법:( 이 숫자를 Excel에 입력하면 소수점 이하 두 자리까지 반올림한 후 올바른 결과를 받게 됩니다.
3.314 -> 3.31
3.315 -> 3.32
8.124 -> 8.12
8.125 -> 8.13
BASH에서 정확한 결과를 얻는 방법은 무엇입니까? printf
사용해 보았지만 awk
같은 결과를 얻지 못했습니다.
prompt> printf '%.*f\n' 2 8.125
8.12
prompt> echo '8.125' | awk '{printf("%.2f\n", $1)}'
8.12
답변1
printf '%.2f\n' 8.125
8.125
strtod()
십진수의 텍스트 표현은 표준 또는 C 함수 strtold()
와 같은 방법을 사용하여 내부 이진 표현으로 변환되어 결과적으로 double
이진 long double
부동 소수점 숫자가 되며, 내부 표현은 C 컴파일러 및 컴퓨터 아키텍처에 따라 달라집니다.
그런 다음 숫자는 명령을 통해 표준 함수(또는 결과를 문자열로 반환하는 변형) printf
로 전달되며, 이 함수는 다시 리터럴 십진수 표현으로 변환하고 반올림합니다. printf()
가장 가까운 짝수로 반올림, 짝수로 반올림(라고도 함)은행가 반올림).
학교에서 배운 방법은 평균적으로(양수의 경우) 과대평가하는 경향이 있다는 점에서 편향되어 있습니다. 반이 짝수인 경우 8.125
합계 8.115
는 8.12
(2
심지어), 한 비트는 반올림되고 한 비트는 반올림됩니다. 큰 숫자의 경우 숫자의 절반을 반올림하고 나머지 절반을 반올림해도 체계적인 편향이 발생하지 않습니다.
이제 이는 이진수로 정확하게 표현될 수 있는 숫자에만 적용됩니다.
공교롭게도 8.125는 이진수로 표현될 수 있습니다. 그것은 2 3 + 2 -3 입니다 . 8.135호 가장 가까운 IEEE 754 배정밀도 이진수는 8.1349999999999997868371792719699442386627197265625(10진수로 다시 변환할 때)이므로 짝수(8.14)가 아닌 가장 가까운 8.13으로 변환됩니다.
따라서 원하는 것을 수행하려면(적절한 은행 반올림도 수행) 이진수에서는 작동하지 않지만 십진수에서는 작동하는 것이 필요합니다. 따라서 유틸리티 를 printf()
포함하여 아래에서 사용 되거나 더 일반적으로 이진수를 처리하는 프로세서의 부동 소수점 산술 함수와 함께 작동하는 것은 불가능합니다.printf
awk
printf()
numfmt
python3
예를 들어 다음과 decimal
같은 모듈을 사용할 수 있습니다 .@marcelm이 표시함) perl
또는Math::BigFloat
기준 치수그리고그것은 bfround()
기능 이다. 기본적으로 그들은 그렇습니다은행가 반올림:
$ printf '%s\n' 1.1{0..5}5 | perl -MMath::BigFloat -lne 'print "$_ -> " . Math::BigFloat->new($_)->bfround(-2)'
1.105 -> 1.10
1.115 -> 1.12
1.125 -> 1.12
1.135 -> 1.14
1.145 -> 1.14
1.155 -> 1.16
하지만 다음으로 전환할 수 있습니다.common
모델이는 학교에서 배운 내용과 일치합니다.
$ printf '%s\n' {-,}1.1{0..5}5 +825e-3 0xAAp-6 0x1p100 nan Infinity |
perl -MMath::BigFloat -lne '
print "$_ -> " . Math::BigFloat->new($_)->bfround(-2,common)'
-1.105 -> -1.11
-1.115 -> -1.12
-1.125 -> -1.13
-1.135 -> -1.14
-1.145 -> -1.15
-1.155 -> -1.16
1.105 -> 1.11
1.115 -> 1.12
1.125 -> 1.13
1.135 -> 1.14
1.145 -> 1.15
1.155 -> 1.16
+825e-3 -> 0.83
0xAAp-6 -> 2.66
0x1p100 -> 1267650600228229401496703205376.00
nan -> NaN
Infinity -> inf
(다른 기호를 사용하는 추가 숫자가 표시됩니다).
like python3
의 메소드는 numfmt
일부 printf
유틸리티 구현과 달리 로케일을 구분하지 않습니다. 특히, 10진수 기수 문자는 또는 로케일 .
에서도 입력 및 출력 에 사용됩니다 .,
٫
답변2
시스템이 GNU coreutils를 사용하는 경우숫자명령을 사용할 수 있어야 하며 "위로", "아래로", "0에서"(기본값), "0으로" 또는 "가장 가까운" 반올림 중에서 선택할 수 있습니다.
예를 들어(여기서는 소수점 기본 문자가 로케일에서 .
):
$ numfmt --round=nearest --format %.2f << EOF
3.314
3.315
8.124
8.125
EOF
3.31
3.32
8.12
8.13
답변3
정수로 반올림하는 표준 방법은 ½을 더하고 자르는 것입니다.
printf '%s\n' 1.5 2.5 3.5 4.5 |
awk '{ print int($1 +.5) }'
소수점 이하 두 자리에 100을 곱하려면 자르고 다시 나누세요.
printf '%s\n' 3.314 3.315 8.124 8.125 |
awk '{ print int(100*$1 +.5)/100 }'
또는
printf '%s\n' 3.314 3.315 8.124 8.125 |
awk '{ printf "%0.2f\n", int(100*$1 +.5)/100 }'
답변4
파이썬 사용
python3 -c 'import decimal, sys; print(round(decimal.Decimal(sys.argv[1]), ndigits=2))' 3.314
Python은 Decimal
대부분의 다른 답변에서 발생하는 부동 소수점 정밀도 문제 없이 기본 10진수를 무제한 정밀도로 정확하게 나타냅니다.
존재하다decimal
기본 컨텍스트Python은 round()
절반 값을 짝수로 반올림합니다(뱅커 반올림이라고 함). 이는 편향을 도입하지 않기 때문에 일반적으로 선호되는 반올림 방법입니다.
예제 출력:
3.314 -> 3.31
3.315 -> 3.32
8.124 -> 8.12
8.125 -> 8.12
10000.195 -> 10000.20
원하는 동작을 얻기 위해 0에서 반올림할 수도 있습니다.
$ python3 -c 'import sys; from decimal import *; getcontext().rounding = ROUND_HALF_UP; print(round(Decimal(sys.argv[1]),2))' 8.125
8.13
이는 8.125를 8.13으로 반올림하고 -8.125를 -8.13으로 반올림합니다.
getcontect().prec
10 26 이상(또는 -10 26 이하) 으로 반올림될 수 있는 숫자를 처리해야 하는 경우 값을 늘립니다(기본값은 28).
바라보다이 decimal
문서더 알아보기.
1은 다음 공식에 의해 결정됩니다.문맥의 //prec
Emin
Emax
매우 큰(무한은 아니지만) 최대값을 갖습니다.