bash
In bash
, probabilmente è buono come si arriva. Questo utilizza un shell incorporato. Se hai bisogno del risultato in una variabile, puoi usare la sostituzione dei comandi o lo bash
specifico (anche se ora supportato anche da zsh
):
printf -v int %.0f "$float"
Potresti fare:
float=1.23
int=${float%.*}
Ma ciò eliminerebbe la parte frazionaria invece di darti il numero intero più vicino e che non funzionerebbe per valori di $float
like 1.2e9
o .12
per esempio.
Si noti inoltre le possibili limitazioni dovute alla rappresentazione interna dei galleggianti:
$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
Ottieni un numero intero, ma è probabile che non sarai in grado di utilizzare quel numero intero da nessuna parte.
Inoltre, come notato da @BinaryZebra, in diverse printf
implementazioni (bash, ksh93, yash, non GNU, zsh, dash), è influenzato dalla locale (il separatore decimale che può essere .
o ,
).
Quindi, se i tuoi float sono sempre espressi con il punto come separatore decimale e vuoi che sia trattato come tale printf
indipendentemente dalle impostazioni locali dell'utente che invoca il tuo script, dovrai correggere le impostazioni locali su C:
LC_ALL=C printf '%.0f' "$float"
Con yash
, puoi anche fare:
printf '%.0f' "$(($float))"
(vedi sotto).
POSIX
printf "%.0f\n" 1.1
non è POSIX in quanto %f
non è necessario che sia supportato da POSIX.
POSIXly, puoi fare:
f2i() {
awk 'BEGIN{for (i=1; i<ARGC;i++)
printf "%.0f\n", ARGV[i]}' "$@"
}
Quello non è influenzato dalle impostazioni locali (la virgola non può essere un separatore decimale in awk
quanto è già un carattere speciale nella sintassi lì ( print 1,2
, come print 1, 2
nel passare due argomenti a print
)
zsh
In zsh
(che supporta l'aritmetica in virgola mobile (il separatore decimale è sempre il punto)), hai la rint()
funzione matematica per darti il numero intero più vicino come float (come in C
) e int()
darti un numero intero da un float (come in awk
). Quindi puoi fare:
$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123
O:
$ integer i=$((rint(5.678e2)))
$ echo $i
568
Tuttavia nota che mentre double
s può rappresentare numeri molto grandi, gli interi sono molto più limitati.
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
ksh93
ksh93 è stata la prima shell tipo Bourne a supportare l'aritmetica in virgola mobile. ksh93 ottimizza la sostituzione dei comandi non usando una pipe o biforcando quando i comandi sono solo comandi incorporati. Così
i=$(printf '%.0f' "$f")
non si biforca. O ancora meglio:
i=${ printf '%.0f' "$f"; }
che non si biforca, ma che non crea problemi con la creazione di un ambiente subshell falso.
Puoi anche fare:
i=$((rint(f)))
Ma attenzione a:
$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19
Puoi anche fare:
integer i=$((rint(f)))
Ma come per zsh
:
$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
Attenzione che l' ksh93
aritmetica in virgola mobile rispetta l'impostazione del separatore decimale nella locale (anche se ,
altrimenti $((1,2))
sarebbe un operatore matematico ( sarebbe 6/5 in una locale francese / tedesca ... e lo stesso di $((1, 2))
2 in una locale inglese) .
Yash
yash supporta anche l'aritmetica in virgola mobile ma non ha funzioni matematiche come ksh93
/ zsh
's rint()
. Puoi convertire un numero in numero intero usando ad esempio il binario o l' operatore (funziona anche in zsh
ma non in ksh93
). Si noti tuttavia che tronca la parte decimale, non ti dà il numero intero più vicino:
$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-9223372036854775808
yash
onora il separatore decimale del locale sull'output, ma non per le costanti letterali in virgola mobile nelle sue espressioni aritmetiche, che possono causare sorprese:
$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator
È buono in un certo senso in quanto puoi usare costanti in virgola mobile nei tuoi script che usano il punto e non devi preoccuparti che smetterà di funzionare in altre versioni locali, ma sarà comunque in grado di gestire i numeri espressi dall'utente per tutto il tempo come ti ricordi di fare:
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