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 bash
konkretnego (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 $float
podobnych 1.2e9
lub .12
na 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 printf
implementacjach (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 printf
liczby 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ą yash
możesz także:
printf '%.0f' "$(($float))"
(patrz poniżej).
POSIX
printf "%.0f\n" 1.1
nie jest POSIX, ponieważ %f
nie 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, awk
ponieważ jest już tam znakiem specjalnym w składni ( print 1,2
tak samo, jak print 1, 2
do 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ż double
s 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 ksh93
arytmetyka 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, zsh
ale 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