Bash

如何將浮點數轉換為整數?

  • May 21, 2020

這是在bash中進行浮點到整數轉換的正確方法嗎?還有其他方法嗎?

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

重擊

bash中,這可能是最好的。它使用內置的 shell。如果您需要變數中的結果,您可以使用命令替換或bash特定的(儘管現在也支持zsh):

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

你可以這樣做:

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

但這會刪除小數部分,而不是為您提供最接近的整數,並且不適用於$floatlike1.2e9.12例如的值。

還要注意由於浮點數的內部表示可能存在的限制:

$ 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,因為 POSIX%f不需要支持。

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()數學函式為您提供最接近的整數作為浮點數(如 in C)並int()為您提供浮點數中的整數(如 in 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 的 shell。當命令只是內置命令時,ksh93 通過不使用管道或分叉來優化命令替換。所以

i=$(printf '%.0f' "$f")

不分叉。甚至更好:

i=${ printf '%.0f' "$f"; }

它也不會分叉,但也不會為創建假的 subshel​​l 環境而煩惱。

你也可以這樣做:

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

引用自:https://unix.stackexchange.com/questions/89712