Arrotondamento di numeri in virgola mobile
Che cosa significa "arrotondare un numero in virgola mobile"?
È facile, ovviamente ... Dov'è il mio libro di matematica da scuola ...
No, sappiamo già che nulla di correlato ai numeri in virgola mobile è facile:
Per cominciare, ci sono più modalità di arrotondamento:
Arrotondamento verso l'alto?
Arrotondamento verso il basso?
Arrotondamento a zero?
Arrotondamento al più vicino - legami con il pareggio?
Arrotondamento al più vicino - legami a partire da zero?
Come gestire le custodie angolari? Come scoprire quali sono i casi d'angolo?
OK, sembra che dovremmo usare un'implementazione dello standard IEEE 754 e lasciare che il nostro sistema se ne occupi.
Per arrotondare un numero in virgola mobile nella shell, basato sull'aritmetica in virgola mobile standard, sono necessari tre passaggi:
- Converti il testo di input da un argomento della riga di comando in un numero a virgola mobile standard.
- Arrotondare il numero in virgola mobile utilizzando la normale implementazione IEEE 754.
- Formatta il numero come stringa per l'output.
Si scopre che il comando shell printf
può fare tutto questo. Può essere utilizzato per stampare numeri secondo una specifica di formato come descritto in man 3 printf
. I numeri sono arrotondati implicitamente nel modo standard se è richiesto per il formato di output:
Il comando
Arrotondare x
alla p
precisione delle cifre con input come argomenti della riga di comando:
printf "%.*f\n" "$p" "$x"
O in una pipeline di shell, con input x
su input standard e p
come argomento:
echo "$x" | xargs printf "%.*f\n" "$p"
Esempi:
$ printf '%.*f\n' 0 6.66
7
$ printf '%.*f\n' 1 6.66
6.7
$ printf '%.*f\n' 2 6.66
6.66
$ printf '%.*f\n' 3 6.66
6.660
$ printf '%.*f\n' 3 6.666
6.666
$ printf '%.*f\n' 3 6.6666
6.667
Trappole cattive
Attenzione alle impostazioni locali! Specifica il separatore tra la parte integrale e la frazione - il .
, come ci si può aspettare.
Ma vedi cosa succede in un locale tedesco, ad esempio:
$ LC_ALL=de_DE.UTF-8 printf '%.*f\n' 3 6.6666
6,667
Sì, è vero 6,667
- sei virgola sei sei sette. Ciò rovinerebbe sicuramente la tua sceneggiatura.
(Ma solo per i due clienti in Germania. Ad eccezione delle macchine per sviluppatori attualmente in fase di debug per questi clienti.)
Più robusto
Per renderlo più robusto, utilizzare:
LC_ALL=C /usr/bin/printf "%.*f\n" "$p" "$x"
o
echo "$x" | LC_ALL=C xargs /usr/bin/printf "%.*f\n" "$p"
Questo utilizza anche al /usr/bin/printf
posto della shell incorporata bash
o zsh
per ovviare a piccole incongruenze nell'implementazione delle printf
varianti e prevenire un effetto molto sporco quando, in una locale tedesca, LC_ALL
è impostato, ma non esportato. Quindi, il builtin usa ,
e /usr/bin/printf
usa .
...
Vedere anche %g
per arrotondare a un numero specificato di cifre significative.
awk
.