grzmotnąć
W bash, to prawdopodobnie tak dobre, jak to możliwe. To używa wbudowanej powłoki. Jeśli potrzebujesz wyniku w zmiennej, możesz użyć podstawienia polecenia lub bashkonkretnego (choć teraz również obsługiwanego przez zsh):
printf -v int %.0f "$float"
Mógłbyś:
float=1.23
int=${float%.*}
Ale to usunęłoby część ułamkową zamiast podać najbliższą liczbę całkowitą i nie działałoby to dla wartości $floatpodobnych 1.2e9lub .12na przykład.
Zwróć również uwagę na możliwe ograniczenia wynikające z wewnętrznej reprezentacji liczb zmiennoprzecinkowych:
$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
Otrzymujesz liczbę całkowitą, ale są szanse, że nigdzie nie będziesz mógł jej użyć.
Ponadto, jak zauważył @BinaryZebra, w kilku printfimplementacjach (bash, ksh93, yash, a nie GNU, zsh, dash) zależy od ustawień regionalnych (separator dziesiętny, którym może być .lub ,).
Jeśli więc printfliczby zmiennoprzecinkowe są zawsze wyrażane za pomocą kropki jako separatora dziesiętnego, a chcesz, aby była traktowana jako taka niezależnie od ustawień regionalnych użytkownika wywołującego skrypt, musisz ustawić ustawienia regionalne na C:
LC_ALL=C printf '%.0f' "$float"
Za pomocą yashmożesz także:
printf '%.0f' "$(($float))"
(patrz poniżej).
POSIX
printf "%.0f\n" 1.1
nie jest POSIX, ponieważ %fnie musi być obsługiwany przez POSIX.
POSIXly możesz:
f2i() {
awk 'BEGIN{for (i=1; i<ARGC;i++)
printf "%.0f\n", ARGV[i]}' "$@"
}
Ustawienia regionalne nie mają na to wpływu (przecinek nie może być separatorem dziesiętnym, awkponieważ jest już tam znakiem specjalnym w składni ( print 1,2tak samo, jak print 1, 2do przekazania dwóch argumentów print)
zsh
W zsh(który obsługuje arytmetykę zmiennoprzecinkową (separatorem dziesiętnym jest zawsze kropka)), masz funkcję rint()matematyczną, która daje ci najbliższą liczbę całkowitą jako liczbę zmiennoprzecinkową (jak w C) i int()daje ci liczbę całkowitą od liczby zmiennoprzecinkowej (jak w awk). Możesz więc zrobić:
$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123
Lub:
$ integer i=$((rint(5.678e2)))
$ echo $i
568
Należy jednak pamiętać, że chociaż doubles może reprezentować bardzo duże liczby, liczby całkowite są znacznie bardziej ograniczone.
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
ksh93
ksh93 była pierwszą powłoką podobną do Bourne'a, która obsługiwała arytmetykę zmiennoprzecinkową. ksh93 optymalizuje podstawianie poleceń, nie używając potoku lub rozwidlenia, gdy polecenia są tylko wbudowanymi poleceniami. Więc
i=$(printf '%.0f' "$f")
nie rozwidla się. Lub nawet lepiej:
i=${ printf '%.0f' "$f"; }
co również nie rozwidla, ale także nie sprawia kłopotów z tworzeniem fałszywego środowiska podpowłoki.
Możesz także:
i=$((rint(f)))
Ale uważaj na:
$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19
Możesz także:
integer i=$((rint(f)))
Ale jak dla zsh:
$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
Strzeż się, że ksh93arytmetyka zmiennoprzecinkowa honoruje ustawienie separatora dziesiętnego w ustawieniach narodowych (mimo że w ,przeciwnym razie jest operatorem matematycznym ( $((1,2))w ustawieniach francuskich / niemieckich ... byłoby 6/5, a to samo co $((1, 2))2 w ustawieniach angielskich) .
yash
Yash obsługuje również arytmetyki zmiennoprzecinkowej, ale nie ma funkcji matematycznych, takich jak ksh93/ zsh„s rint(). Możesz jednak przekonwertować liczbę na liczbę całkowitą, używając na przykład operatora binarnego lub operatora (działa również w trybie in, zshale nie w trybie in ksh93). Zauważ jednak, że obcina on część dziesiętną, nie podaje najbliższej liczby całkowitej:
$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-9223372036854775808
yash honoruje separator dziesiętny ustawienia narodowego na wyjściu, ale nie dla stałych literału zmiennoprzecinkowego w wyrażeniach arytmetycznych, co może powodować niespodzianki:
$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator
Jest to dobre, ponieważ możesz używać stałych zmiennoprzecinkowych w swoich skryptach, które używają kropki i nie musisz się martwić, że przestanie działać w innych lokalizacjach, ale nadal będzie w stanie poradzić sobie z liczbami wyrażonymi przez użytkownika tak długo, jak długo jak pamiętasz, aby zrobić:
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