이것이 bash에서 부동 소수점을 정수로 변환하는 올바른 방법입니까? 다른 방법이 있나요?
flotToint() {
printf "%.0f\n" "$@"
}
답변1
세게 때리다
에서는 bash
이것이 이미 최고일 수도 있습니다. 쉘 내장 함수를 사용합니다. 변수에 결과가 필요한 경우 명령 대체 또는 bash
특정 명령을 사용할 수 있습니다(현재도 지원됨 zsh
).
printf -v int %.0f "$float"
다음을 수행할 수 있습니다.
float=1.23
int=${float%.*}
$float
하지만 이는 가장 가까운 정수를 제공하는 대신 소수 부분을 제거하며, 1.2e9
또는 example과 같은 .12
값에는 작동하지 않습니다 .
또한 부동 소수점 숫자의 내부 표현으로 인해 발생할 수 있는 제한 사항에 유의하세요.
$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
정수를 얻을 수 있지만 그 정수를 어디에서나 사용할 수 없을 가능성이 높습니다.
또한 @BinaryZebra가 지적했듯이 여러 printf
구현(bash, ksh93, yash, zsh, dash 또는 이전 버전의 GNU 제외 printf
)에서는 로캘의 영향을 받습니다(소수 구분 기호는 .
, ,
또는 일 수 있음 ٫
).
따라서 부동 소수점이 항상 마침표를 소수 구분 기호로 사용하여 표시되고 스크립트를 호출하는 사용자의 로케일에 관계없이 부동 소수점이 그렇게 처리되도록 하려면 printf
로케일을 C로 수정해야 합니다.
LC_ALL=C printf '%.0f' "$float"
를 사용하면 yash
다음 작업도 수행할 수 있습니다.
printf '%.0f' "$(($float))"
(아래 참조).
POSIX
printf "%.0f\n" 1.1
%f
POSIX는 지원이 필요하지 않으므로 POSIX가 아닙니다 .
POSIXly에서는 다음과 같이 할 수 있습니다.
f2i() {
LC_ALL=C awk -- '
BEGIN {
for (i = 1; i < ARGC; i++)
printf "%.0f\n", ARGV[i]
}' "$@"
}
awk
언어 구문의 리터럴 숫자는 항상 .
소수점 문자( ,
인수를 구분하는 데 사용되므로 숫자에 사용할 수 없음) 로 사용 되지만 ARGV
일부 구현에서는 여기에서와 같이 입력에서 숫자를 가져올 때 로케일 설정을 존중합니다. GNU의 경우 이는 awk
환경 내에서만 적용됩니다.$POSIXLY_CORRECT
다루기 힘든
(부동 소수점 산술 지원(소수 구분 기호는 항상 마침표임)) 에서는 가장 가까운 정수를 부동 소수점으로 제공하고( 에서처럼 ) 부동소수점에서 정수를 제공하는 수학 함수를 zsh
사용할 수 있습니다 ( middle 에서처럼 ). 그래서 당신은 이것을 할 수 있습니다 :rint()
C
int()
awk
$ zmodload zsh/mathfunc
$ i=$(( int(rint(1.234e2)) ))
$ echo $i
123
또는:
$ integer i=$(( rint(5.678e2) ))
$ echo $i
568
그러나 double
s는 매우 큰 숫자를 나타낼 수 있지만 정수는 훨씬 더 제한적입니다.
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
크쉬 93
ksh93은 부동 소수점 연산을 지원하는 최초의 Bourne 유사 셸입니다. ksh93은 명령이 내장된 경우 파이프나 포크를 사용하지 않음으로써 명령 대체를 최적화합니다. 그래서
i=$(printf '%.0f' "$f")
분할 종료가 없습니다. 또는 더 나은 방법은 다음과 같습니다.
i=${ printf '%.0f' "$f"; }
가짜 서브쉘 환경을 생성하는 데 어려움을 겪거나 포크하지도 않습니다.
다음과 같이 할 수도 있습니다.
i=$(( rint(f) ))
하지만 조심하세요:
$ echo "$(( rint(1e18) ))"
1000000000000000000
$ echo "$(( rint(1e19) ))"
1e+19
다음과 같이 할 수도 있습니다.
integer i=$(( rint(f) ))
그러나 다음과 같습니다 zsh
:
$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
부동 소수점 산술 은 ksh93
로케일의 소수 구분 기호 설정을 따릅니다( ,
수학 연산자( $((1,2))
프랑스어/독일어... 로케일의 경우 6/5, $((1, 2))
영어 로케일의 2와 동일)).
야쉬
yash는 부동 소수점 연산도 지원하지만 ksh93
/ zsh
etc 수학 함수는 지원하지 않습니다 rint()
. 다음을 사용하여 숫자를 정수로 변환할 수 있습니다.바이너리 또는예: 연산자(이 역시 작동 zsh
하지만 에는 적용되지 않음 ksh93
). 그러나 소수 부분은 잘라내지만 가장 가까운 정수는 제공하지 않습니다.
$ echo "$(( 0.237e2 | 0 ))"
23
$ echo "$(( 1e19 | 0 ))"
-9223372036854775808
yash
출력에서 로케일의 소수 구분 기호를 고려하지만 산술 표현식의 부동 소수점 리터럴 상수는 고려하지 않습니다. 이로 인해 예상치 못한 결과가 발생할 수 있습니다.
$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator
마침표를 사용하는 스크립트에서 다른 로케일에서 작업이 중단되는 것에 대해 걱정할 필요 없이 부동 소수점 상수를 사용할 수 있지만 다음과 같이 기억하는 한 사용자 표시 숫자를 계속 처리할 수 있기 때문에 어떤 면에서는 좋습니다.
var=$((10.3)) # and not var=10.3
... "$((a + 0.1))" # and not "$(($a + 0.1))".
printf '%.0f\n' "$((10.3))" # and not printf '%.0f\n' 10.3
답변2
bc
- 임의의 정밀 계산기 언어
int(float)는 다음과 같아야 합니다:
$ echo "$float/1" | bc
1234
더 나은 반올림을 위해서는 다음 명령을 사용하십시오.
$ echo "($float+0.5)/1" | bc
예:
$ float=1.49
$ echo "($float+0.5)/1" | bc
1
$ float=1.50
$ echo "($float+0.5)/1" | bc
2
답변3
아주 간단한 해키는
function float_to_int() {
echo $1 | cut -d. -f1 # or use -d, if decimals separator is ,
}
샘플 출력
$ float_to_int 32.333
32
$ float_to_int 32
32
답변4
관련된:
보완적인@stefanchazeras awk
답변:
float_to_integer_rounding_nearst() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%.0f", ARGV[i]}' "$@";
}
float_to_integer_rounding_floor() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%d", int( ARGV[i] )}' "$@";
}