부동 소수점 숫자를 정수로 변환하는 방법은 무엇입니까?

부동 소수점 숫자를 정수로 변환하는 방법은 무엇입니까?

이것이 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

%fPOSIX는 지원이 필요하지 않으므로 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()Cint()awk

$ zmodload zsh/mathfunc
$ i=$(( int(rint(1.234e2)) ))
$ echo $i
123

또는:

$ integer i=$(( rint(5.678e2) ))
$ echo $i
568

그러나 doubles는 매우 큰 숫자를 나타낼 수 있지만 정수는 훨씬 더 제한적입니다.

$ 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/ zshetc 수학 함수는 지원하지 않습니다 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

관련된:

  1. awk에서 부동 소수점 숫자를 정수로 변환하는 방법,
  2. 쉘에서 부동 소수점 숫자를 반올림하는 방법은 무엇입니까?

보완적인@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] )}' "$@";
}

관련 정보