Est-ce la bonne façon de faire une conversion float en entier dans bash? Existe-t-il une autre méthode?
flotToint() {
printf "%.0f\n" "$@"
}
Dans bash
, c'est probablement aussi bon que possible. Cela utilise un shell intégré. Si vous avez besoin du résultat dans une variable, vous pouvez utiliser la substitution de commandes ou la spécification bash
(bien que maintenant également prise en charge par zsh
):
printf -v int %.0f "$float"
Vous pourriez faire:
float=1.23
int=${float%.*}
Mais cela supprimerait la partie fractionnaire au lieu de vous donner l'entier le plus proche et cela ne fonctionnerait pas pour des valeurs de $float
Comme 1.2e9
Ou .12
Par exemple.
Notez également les limitations possibles dues à la représentation interne des flotteurs:
$ printf '%.0f\n' 1e50
100000000000000007629769841091887003294964970946560
Vous obtenez un entier, mais il est probable que vous ne pourrez pas utiliser cet entier n'importe où.
De plus, comme indiqué par @BinaryZebra, dans plusieurs implémentations printf
(bash, ksh93, yash, pas GNU, zsh, dash), il est affecté par les paramètres régionaux (le séparateur décimal qui peut être .
ou ,
).
Donc, si vos flottants sont toujours exprimés avec le point comme séparateur décimal et que vous souhaitez qu'il soit traité comme tel par printf
, indépendamment des paramètres régionaux de l'utilisateur qui appelle votre script, vous devez corriger les paramètres régionaux à C:
LC_ALL=C printf '%.0f' "$float"
Avec yash
, vous pouvez également faire:
printf '%.0f' "$(($float))"
(voir ci-dessous).
printf "%.0f\n" 1.1
n'est pas POSIX car %f
ne doit pas être pris en charge par POSIX.
POSIX, vous pouvez faire:
f2i() {
awk 'BEGIN{for (i=1; i<ARGC;i++)
printf "%.0f\n", ARGV[i]}' "$@"
}
Celui-ci n'est pas affecté par les paramètres régionaux (la virgule ne peut pas être un séparateur décimal dans awk
car il y a déjà un caractère spécial dans la syntaxe (print 1,2
, Identique à print 1, 2
Pour passez deux arguments à print
)
Dans zsh
(qui prend en charge l'arithmétique à virgule flottante (le séparateur décimal est toujours le point)), vous disposez de la fonction mathématique rint()
pour vous donner l'entier le plus proche sous forme de flottant (comme dans C
) et int()
pour vous donner un entier à partir d'un flottant (comme dans awk
). Vous pouvez donc faire:
$ zmodload zsh/mathfunc
$ i=$((int(rint(1.234e2))))
$ echo $i
123
Ou:
$ integer i=$((rint(5.678e2)))
$ echo $i
568
Notez cependant que si double
peut représenter de très grands nombres, les entiers sont beaucoup plus limités.
$ printf '%.0f\n' 1e123
999999999999999977709969731404129670057984297594921577392083322662491290889839886077866558841507631684757522070951350501376
$ echo $((int(1e123)))
-9223372036854775808
ksh93 a été le premier shell de type Bourne à prendre en charge l'arithmétique à virgule flottante. ksh93 optimise la substitution de commandes en n'utilisant pas de canal ou de fourche lorsque les commandes ne sont que des commandes intégrées. Donc
i=$(printf '%.0f' "$f")
ne bifurque pas. Ou encore mieux:
i=${ printf '%.0f' "$f"; }
ce qui ne débouche pas non plus mais ne va pas non plus se donner la peine de créer un faux environnement de sous-shell.
Vous pouvez également faire:
i=$((rint(f)))
Mais attention:
$ echo "$((rint(1e18)))"
1000000000000000000
$ echo "$((rint(1e19)))"
1e+19
Vous pourriez également faire:
integer i=$((rint(f)))
Mais comme pour zsh
:
$ integer i=1e18
$ echo "$i"
1000000000000000000
$ integer i=1e19
$ echo "$i"
-9223372036854775808
Attention, l'arithmétique à virgule flottante ksh93
Respecte le paramètre du séparateur décimal dans les paramètres régionaux (même si ,
Est autrement un opérateur mathématique ($((1,2))
serait 6/5 dans un français/Allemand ... locale, et la même chose que $((1, 2))
, c'est-à-dire 2 dans une locale anglaise).
yash prend également en charge l'arithmétique à virgule flottante mais n'a pas de fonctions mathématiques comme rint()
de ksh93
/zsh
. Vous pouvez cependant convertir un nombre en entier en utilisant l'opérateur binaire o par exemple (fonctionne également dans zsh
mais pas dans ksh93
). Notez cependant qu'il tronque la partie décimale, il ne vous donne pas l'entier le plus proche:
$ echo "$((0.237e2 | 0))"
23
$ echo "$((1e19))"
-9223372036854775808
yash
honore le séparateur décimal des paramètres régionaux en sortie, mais pas pour les constantes littérales à virgule flottante dans ses expressions arithmétiques, ce qui peut provoquer des surprises:
$ LC_ALL=fr_FR.UTF-8 ./yash -c 'a=$((1e-2)); echo $(($a + 1))'
./yash: arithmetic: `,' is not a valid number or operator
C'est une bonne chose dans la mesure où vous pouvez utiliser des constantes à virgule flottante dans vos scripts qui utilisent la période et ne pas avoir à vous soucier que cela cessera de fonctionner dans d'autres paramètres régionaux, mais tout de même être capable de gérer les nombres exprimés par l'utilisateur aussi longtemps comme vous vous en souvenez:
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
bc
- Un langage de calculatrice à précision arbitraire
int (float) devrait ressembler à:
$ echo "$float/1" | bc
1234
Pour arrondir mieux utiliser ceci:
$ echo "($float+0.5)/1" | bc
Exemple:
$ float=1.49
$ echo "($float+0.5)/1" | bc
1
$ float=1.50
$ echo "($float+0.5)/1" | bc
2
La réponse précédente soumise était presque correcte: "Vous pourriez faire:
float=1.23
int=${float%.*}
Mais cela supprimerait la partie fractionnaire au lieu de vous donner l'entier le plus proche et cela ne fonctionnerait pas pour les valeurs de $ float comme 1.2e9 ou .12 par exemple .... "
Utilisez simplement ${float%%.*}
.
echo ${float%%.*}
1
installez le programme de bip avec:
aptitude install beep
or
apt-get install beep
et écoutez la fonction sinus comme ceci:
1a. définir la fonction en bash:
$ function sinus ()
{
a=$1;
b=$2;
n=$3;
f=$4;
d=$(echo "scale=$f; ($b-$a)/$n"|bc);
for m in $(seq 0 $n);
do
x=$(echo "scale=$f;$a+$m*$d"|bc);
y=$(echo "scale=$f;s($x)"|bc -l);
#printf "%0.${f}f\t" "$x";
#printf "%0.${f}f\n" "$y";
z=$(echo "scale=$f; 2300+2000*$y" | bc);
beep -f "$z" -l 2 -d 0;
done | column -t
}
2a. Appelez cette fonction comme ceci:
$ sinus 1 20 300 4
Note: 'sinus abnf' signifie écouter le son du sinus (en radians) de a à b divisant l'intervalle en n + 1 parties égales en utilisant f décimales. Il y a plus de choses que nécessaire dans la fonction car vous pouvez les utiliser pour tracer ou tout autre chose. Vous pouvez également écrire lire un b n f au lieu des initialisations.
Aussi, très drôle, écraser de plus en plus les cycles de la fonction sinus jusqu'à ce que le programme ne le supporte pas:
1b. définir:
$ function sinus-inv ()
{
a=$1; b=$2; n=$3; f=$4;
d=$(echo "scale=$f; ($b-$a)/$n"|bc);
for m in $(seq 1 $n);
do
x=$(echo "scale=$f;$a+$m*$d"|bc);
y=$(echo "scale=$f;s(8000/($b-$x))"|bc -l);
z=$(echo "scale=$f; 2300+2000*$y" | bc);
beep -f "$z" -l 1 -d 0;
done;
}
2b. Exemple d'appel:
$ sinus-inv 1 100 1000 8
Un hacky très simple est
function float_to_int() {
echo $1 | cut -d. -f1 # or use -d, if decimals separator is ,
}
Exemple de sortie
$ float_to_int 32.333
32
$ float_to_int 32
32
En relation:
Compléter @ Stéphane Chazelasawk
réponse:
float_to_integer_rounding_nearst() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%.0f", ARGV[i]}' "$@";
}
float_to_integer_rounding_floor() {
awk 'BEGIN{for (i=1; i<ARGC;i++) printf "%d", int( ARGV[i] )}' "$@";
}