명령줄에서 IEEE 754 부동 소수점 숫자를 올바르게 반올림하는 방법은 무엇입니까?
출력 숫자의 정밀도(소수점 이하 자릿수)를 지정하고 싶습니다.
예를 들어 6.66
정밀도에 맞게 반올림 1
해야 합니다. 6.7
자세한 내용은 아래 표를 참조하세요.
Value Precision Rounded
6.66 0 7
6.66 1 6.7
6.66 2 6.66
6.66 3 6.660
6.666 3 6.666
6.6666 3 6.667
이는 대화형 셸에서 작동해야 하지만 이상적으로는 프로덕션 셸 스크립트에서 사용할 수 있을 만큼 강력합니다.
답변1
둥근 부동 소수점 숫자
"부동 소수점 수 반올림"이란 무엇을 의미합니까?
간단한 것 같군요... 우리 학교 수학책은 어디에 있나요...
아니요, 우리는 부동 소수점 숫자와 관련된 일이 쉽지 않다는 것을 이미 알고 있습니다.
첫째, 다양한 반올림 모드가 있습니다.
모으다?
반올림 하시겠습니까?
0으로 반올림하시겠습니까?
가장 가까운 값으로 반올림 - 짝수인가요?
가장 가까운 값으로 반올림 - 0에서 멀어지나요?
극단적인 상황에 대처하는 방법은 무엇입니까? 어떤 경우가 극단적인 경우인지 어떻게 알 수 있나요?
좋습니다. IEEE 754 표준 구현을 사용하고 시스템에서 이를 처리하도록 하는 것이 더 나을 것 같습니다.
표준 부동 소수점 산술을 기반으로 셸에서 부동 소수점 숫자를 반올림하려면 다음 세 단계가 필요합니다.
- 명령줄 인수의 입력 텍스트를 표준 부동 소수점 숫자로 변환합니다.
- 부동 소수점 숫자는 일반적인 IEEE 754 구현을 사용하여 반올림됩니다.
- 출력을 위해 숫자를 문자열로 형식화합니다.
쉘 명령으로 밝혀졌습니다printf
모든 것을 할 수 있습니다. 에 설명된 대로 형식 사양에 따라 숫자를 인쇄하는 데 사용할 수 있습니다.man 3 printf
. 출력 형식에서 요구하는 경우 숫자는 표준 방식으로 암시적으로 반올림됩니다.
주문하다
입력을 명령줄 인수로 사용하여 x
숫자 정밀도로 반올림합니다.p
printf "%.*f\n" "$p" "$x"
또는 셸 파이프라인에서 x
표준 입력을 입력 및 p
인수로 사용합니다.
echo "$x" | xargs printf "%.*f\n" "$p"
예:
$ printf '%.*f\n' 0 6.66
7
$ printf '%.*f\n' 1 6.66
6.7
$ printf '%.*f\n' 2 6.66
6.66
$ printf '%.*f\n' 3 6.66
6.660
$ printf '%.*f\n' 3 6.666
6.666
$ printf '%.*f\n' 3 6.6666
6.667
나쁜 함정
영토를 조심하세요! .
예상한 대로 정수 부분과 분수 부분 사이의 구분 기호를 지정합니다.
하지만 독일어 로케일에서는 어떤 일이 일어나는지 확인해 보세요. 예를 들면 다음과 같습니다.
$ LC_ALL=de_DE.UTF-8 printf '%.*f\n' 3 6.6666
6,667
네, 맞아요. 6,667
쉼표 여섯 여섯 여섯 일곱. 이것은 확실히 스크립트를 엉망으로 만들 것입니다.
(그러나 독일의 두 고객에게만 해당됩니다. 현재 해당 고객을 위해 디버깅 중인 개발자 컴퓨터는 예외입니다.)
더 강하게
더욱 강력하게 만들려면 다음을 사용하세요.
LC_ALL=C /usr/bin/printf "%.*f\n" "$p" "$x"
또는
echo "$x" | LC_ALL=C xargs /usr/bin/printf "%.*f\n" "$p"
또한 변형 구현의 사소한 불일치를 해결하고 독일어 로케일로 설정했지만 내보낼 수 없는 경우 매우 더러운 효과를 방지하기 위해 /usr/bin/printf
내장된 셸 대신 bash
OR를 사용합니다. 그런 다음 내장된 을 사용 하고 ...zsh
printf
LC_ALL
,
/usr/bin/printf
.
%g
지정된 유효 숫자 수로 반올림을 참조하세요 .
답변2
내가 찾은 것을 깨끗하게 읽는 가장 쉬운 방법은 다음과 같습니다.
$ print "%.2f" $(bc <<< "0.10765432*100)
10.77
이제 5
다음으로 변경하세요.4
10.76
읽기 쉽고 짧기 때문에 유지관리가 쉽습니다.
답변3
다음은 나를 위해 일했습니다.
#!/bin/bash
function float() {
bc << EOF
num = $1;
base = num / 1;
if (((num - base) * 10) > 1 )
base += 1;
print base;
EOF
echo ""
}
float 3.2