부동 소수점 숫자를 정수로 변환하는 방법?


46

이것은 bash에서 부동 소수점을 정수로 변환하는 올바른 방법입니까? 다른 방법이 있습니까?

flotToint() {
    printf "%.0f\n" "$@"
}

5
"올바른"이란 무엇입니까?
Joseph R.

난 그냥 확인하고 .. 이것이 맞습니까 아니면 이것보다 더 나은가요?
Rahul Patil

2
%.0f반올림 또는 내림됩니다. 너가 원하는게 그거야? printf "%d\n" "$@" 2>/dev/null분수를자를 때 사용할 수 있습니다 .
ott--

답변:


68

세게 때리다

에서 bash, 아마 그것이 얻는만큼 좋을 것입니다. 그것은 쉘 내장을 사용합니다. 변수에 결과가 필요한 경우 명령 대체 또는 bash특정을 사용할 수 있습니다 (이제도 지원합니다 zsh).

printf -v int %.0f "$float"

당신은 할 수 있습니다 :

float=1.23
int=${float%.*}

그러나 가장 가까운 정수를 제공하는 대신 분수 부분을 제거하면 $floatlike 1.2e9또는 예 .12를 들어 값이 작동하지 않습니다 .

또한 float의 내부 표현으로 인한 가능한 제한 사항에 유의하십시오.

$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560

정수를 얻지 만 그 정수를 어디서나 사용할 수는 없습니다.

또한 @BinaryZebra가 지적한 것처럼 여러 printf구현 (Bash, ksh93, yash, GNU가 아닌 zsh, dash)에서 로케일 ( .또는 소수 자릿수 구분 기호)의 영향을받습니다 ,.

따라서 부동 소수점이 항상 마침표로 소수 구분 기호로 표시되고 printf스크립트를 호출하는 사용자의 로캘 에 관계없이 그대로 처리 하려면 로캘을 C로 수정해야합니다.

LC_ALL=C printf '%.0f' "$float"

로에게 yash, 당신은 또한 할 수 있습니다 :

printf '%.0f' "$(($float))"

(아래 참조).

POSIX

printf "%.0f\n" 1.1

POSIX %f가 지원하지 않아도되므로 POSIX 가 아닙니다.

POSIXly, 당신은 할 수 있습니다 :

f2i() {
  awk 'BEGIN{for (i=1; i<ARGC;i++)
   printf "%.0f\n", ARGV[i]}' "$@"
}

하나는 로케일의 영향을받지 않습니다 (쉼표는 awk이미 구문의 특수 문자 print 1,2이므로 print 1, 2두 개의 인수를 전달하는 것과 동일하므로 소수 구분 기호는 사용할 수 없습니다 print)

zsh

에서 zsh(소수점이 항상 기간) 인 부동 소수점 연산 지원 (), 당신은이 rint()float로 (처럼 당신에게 가장 가까운 정수를주는 연산 기능 C) 및 int()(처럼 부동 소수점에서 당신에게 정수를 줄을 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

ksh93

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'들 rint(). 예를 들어 바이너리 또는 연산자를 사용하여 숫자를 정수로 변환 할 수 있습니다 (작동 zsh하지만 작동 하지 않음 ksh93). 그러나 소수점 이하 자릿수를 자르므로 가장 가까운 정수는 제공하지 않습니다.

$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-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

int=${float%.*}Mac의 bash (버전 3.2.57 (1)-릴리스) 스크립트 (버전 10.13.4 (17E199))에서 매우 잘 작동했습니다.
TelamonAegisthus

당신이 첫번째 제제는 GNU bash는 4.4.19, 예를 들면 실패 :```$가 $ 최대 32.800 $의 printf -v INT % .0f "$ 최대"bash는 에코 : printf와 : 32.800 : 올바르지 않은 숫자```
루이스 드 수사

@ LuísdeSousa, 로케일은 아마도 ,10 진 기수 일 것입니다. 에 대한 섹션을 참조하십시오LC_ALL=C
스테판 Chazelas가

참고이 대답은 다른 질문에 답한다는 : 점 자리수를 제거하는 방법 : 질문을 받았다없는 것을 무슨 권리 정수로 플로트를하는 방법 .
아이작

이 방법을 여러 비트의 부동 소수점에 적용해야합니까? 23 비트 또는 128 비트 가수의 부동 소수점에 대해 동일해야합니까?
아이작

21

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

4
그러나 float=-2; echo "($float+0.5)/1" | bc제공합니다 -1.
Stéphane Chazelas

2
이를 + inf를 향해 반올림합니다. 그것은 반올림 가능한 네 가지 방법 중 하나입니다 .

5

제출 된 이전 답변은 거의 정확했습니다. "당신은 할 수 있습니다 :

float=1.23
int=${float%.*}

그러나 이것은 가장 가까운 정수를 제공하는 대신 분수 부분을 제거하고 1.2e9 또는 .12와 같은 $ float 값에는 작동하지 않습니다 .... "

그냥 사용하십시오 ${float%%.*}.

echo ${float%%.*}
1

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

사용할 수 sed는 있지만 cut솔루션이 더 간단합니다. 내가 선호하는 sed또는 cut그들보다 임베디드 타겟에 IMHO 더 사용할 수있는대로 awk(를 통해 여전히 매우 일반적인 busybox것보다 bc).
pevik

0

관련 :

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

@ Stéphane Chazelas 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] )}' "$@";
}

내 awks에서 후자는 0에서 무한대로 빼지 않고 반올림합니다 ( "바닥"을 의미 할 수 있음). 또한 첫 번째 반은 반으로 짝수로 반올림합니다. 그것이 Bash와 다른지 printf또는 builtin보다 awk를 선호하는 다른 이유가 있는지 확실 하지 않습니다 printf.
ilkkachu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.