Comment arrondir un nombre à virgule flottante en Perl?
-
05-07-2019 - |
Question
Comment puis-je arrondir un nombre décimal (virgule flottante) au nombre entier le plus proche?
par exemple
1.2 = 1
1.7 = 2
La solution
Résultat de perldoc -q round
Est-ce que Perl a une fonction round ()? Qu'en est-il de ceil () et de floor ()? Fonctions Trig?N'oubliez pas que
int ()
ne fait que tronquer vers0
. Pour arrondir à un certain nombre de chiffres,sprintf ()
ouprintf ()
est généralement le plus simple. route.
printf("%.3f", 3.1415926535); # prints 3.142
Le module
POSIX
(qui fait partie de la distribution Perl standard) implémenteceil ()
,floor ()
et un certain nombre d'autres éléments mathématiques et trigonométriques les fonctions.
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
La trigonométrie a été effectuée dans les
Math :: Complex
<5.000 à 5.003 perls / a> module. Avec 5.004, le moduleMath :: Trig
(qui fait partie de le standard Perl distribution) implémente les fonctions trigonométriques. Intérieurement utilise le moduleMath :: Complex
et certaines fonctions peuvent échouer hors du axe réel dans le plan complexe, par exemple le sinus inverse de 2.Arrondir les applications financières peut avoir de graves conséquences, et la méthode d'arrondissement utilisée doit être spécifiée avec précision. Dans ces Dans certains cas, il est probablement préférable de ne pas faire confiance à l’arrondi système. utilisé par Perl, mais pour implémenter la fonction d'arrondi dont vous avez besoin toi même.
Pour voir pourquoi, remarquez que vous aurez toujours un problème à mi-chemin. alternance:
for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i} 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
Ne blâmez pas Perl. C'est la même chose que dans C. IEEE dit qu'il faut faire ce. Les nombres Perl dont les valeurs absolues sont des entiers sous
2 ** 31
(le Machines 32 bits) fonctionneront plus ou moins comme des entiers mathématiques. Les autres numéros ne sont pas garantis.
Autres conseils
Même si vous n'êtes pas en désaccord avec les réponses complexes concernant les demi-marques, etc., pour le cas d'utilisation le plus courant (et peut-être trivial):
mon $ arrondi = int ($ float + 0.5);
MISE À JOUR
S'il est possible que votre $ float
soit négatif, la variante suivante produira le résultat correct:
mon $ arrondi = int ($ float + $ float / abs ($ float * 2 || 1));
Avec ce calcul, -1.4 est arrondi à -1, et -1.6 à -2 et le zéro n’explosera pas.
Vous pouvez utiliser un module tel que Math :: Round :
use Math::Round;
my $rounded = round( $float );
Ou vous pouvez le faire grossièrement:
my $rounded = sprintf "%.0f", $float;
Si vous décidez d'utiliser printf ou sprintf, notez qu'ils utilisent Arrondir à moitié selon la méthode.
foreach my $i ( 0.5, 1.5, 2.5, 3.5 ) {
printf "$i -> %.0f\n", $i;
}
__END__
0.5 -> 0
1.5 -> 2
2.5 -> 2
3.5 -> 4
Voir perldoc / perlfaq :
N'oubliez pas que
int ()
ne fait que tronquer vers 0. Pour arrondir à un nombre de chiffres,sprintf ()
ouprintf ()
est généralement le itinéraire le plus facile.printf("%.3f",3.1415926535); # prints 3.142
Le module
POSIX
(élément de la distribution Perl standard) implémenteceil ()
,floor ()
et un certain nombre d'autres éléments mathématiques et fonctions trigonométriques.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
En 5.000 à 5.003 perls, la trigonométrie a été effectuée dans le module
Math :: Complex
.Avec 5.004, le module
Math :: Trig
(élément de la distribution Perl standard) > implémente les fonctions trigonométriques.En interne, il utilise le module
Math :: Complex
et certaines fonctions peuvent ne plus fonctionner. hors de l’axe réel dans le plan complexe, par exemple le sinus inverse de 2.Arrondir les applications financières peut avoir de graves conséquences, et l’arrondi La méthode utilisée doit être spécifiée avec précision. Dans ces cas, il vaut probablement mieux ne pas confiance, quel que soit l'arrondi système utilisé par Perl, mais pour mettre en œuvre le fonction d'arrondissement dont vous avez besoin vous-même.
Pour savoir pourquoi, remarquez que vous aurez toujours un problème d'alternance à mi-parcours:
for ($i = 0; $i < 1.01; $i += 0.05) { printf "%.1f ",$i } 0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7 0.8 0.8 0.9 0.9 1.0 1.0
Ne blâmez pas Perl. C'est la même chose que dans C. IEEE dit qu'il faut faire ce. Les nombres Perl dont les valeurs absolues sont des entiers inférieurs à 2 ** 31 (le Machines 32 bits) fonctionneront plus ou moins comme des entiers mathématiques. Les autres numéros ne sont pas garantis.
Vous n'avez besoin d'aucun module externe.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print Vous n'avez besoin d'aucun module externe.
<*>
Je comprends peut-être votre argument, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif dans l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène le nombre entier positif arrondi respectif uniquement en fonction des décimales. int ($ _), fondamentalement arrondi le nombre afin que ($ -int ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
.' = '.( ( ( Vous n'avez besoin d'aucun module externe.
<*>
Je comprends peut-être votre argument, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif dans l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène le nombre entier positif arrondi respectif uniquement en fonction des décimales. int ($ _), fondamentalement arrondi le nombre afin que ($ -int ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
-int( Vous n'avez besoin d'aucun module externe.
<*>
Je comprends peut-être votre argument, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif dans l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène le nombre entier positif arrondi respectif uniquement en fonction des décimales. int ($ _), fondamentalement arrondi le nombre afin que ($ -int ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
))<0.5) ? int( Vous n'avez besoin d'aucun module externe.
<*>
Je comprends peut-être votre argument, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif dans l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène le nombre entier positif arrondi respectif uniquement en fonction des décimales. int ($ _), fondamentalement arrondi le nombre afin que ($ -int ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
) : int( Vous n'avez besoin d'aucun module externe.
<*>
Je comprends peut-être votre argument, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif dans l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène le nombre entier positif arrondi respectif uniquement en fonction des décimales. int ($ _), fondamentalement arrondi le nombre afin que ($ -int ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
)+1 );
print "\n";
}
Je comprends peut-être votre argument, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif dans l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène le nombre entier positif arrondi respectif uniquement en fonction des décimales. int ($ _), fondamentalement arrondi le nombre afin que ($ -int ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
Les éléments suivants arrondissent les nombres positifs ou négatifs à une position décimale donnée:
sub round ()
{
my ($x, $pow10) = @_;
my $a = 10 ** $pow10;
return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}
Vous trouverez ci-dessous un échantillon de cinq façons différentes de additionner des valeurs. Le premier est un moyen naïf d’effectuer la sommation (et échoue). La seconde tente d’utiliser sprintf ()
, mais elle échoue aussi. Le troisième utilise sprintf ()
avec succès, tandis que les deux derniers (4ème et 5ème) utilisent étage ($ valeur + 0.5)
.
use strict;
use warnings;
use POSIX;
my @values = (26.67,62.51,62.51,62.51,68.82,79.39,79.39);
my $total1 = 0.00;
my $total2 = 0;
my $total3 = 0;
my $total4 = 0.00;
my $total5 = 0;
my $value1;
my $value2;
my $value3;
my $value4;
my $value5;
foreach $value1 (@values)
{
$value2 = $value1;
$value3 = $value1;
$value4 = $value1;
$value5 = $value1;
$total1 += $value1;
$total2 += sprintf('%d', $value2 * 100);
$value3 = sprintf('%1.2f', $value3);
$value3 =~ s/\.//;
$total3 += $value3;
$total4 += $value4;
$total5 += floor(($value5 * 100.0) + 0.5);
}
$total1 *= 100;
$total4 = floor(($total4 * 100.0) + 0.5);
print '$total1: '.sprintf('%011d', $total1)."\n";
print '$total2: '.sprintf('%011d', $total2)."\n";
print '$total3: '.sprintf('%011d', $total3)."\n";
print '$total4: '.sprintf('%011d', $total4)."\n";
print '$total5: '.sprintf('%011d', $total5)."\n";
exit(0);
#$total1: 00000044179
#$total2: 00000044179
#$total3: 00000044180
#$total4: 00000044180
#$total5: 00000044180
Notez que floor ($ valeur + 0.5)
peut être remplacé par int ($ valeur + 0.5)
pour supprimer la dépendance à POSIX
. .
Les nombres négatifs peuvent ajouter certaines bizarreries que les gens doivent connaître.
Les approches de style printf
nous donnent les bons numéros, mais ils peuvent donner des affichages bizarres. Nous avons découvert que cette méthode (à mon avis, stupidement) place dans un signe -
si elle devrait ou non. Par exemple, -0,01 arrondi à une décimale renvoie -0,0, plutôt que 0. Si vous allez utiliser l'approche de style printf
et que vous savez que vous ne voulez pas de décimale, utilisez . % d
et pas % f
(lorsque vous avez besoin de décimales, c'est lorsque l'affichage devient confus).
Bien que ce soit correct et pour les mathématiques, ce n’est pas grave, mais pour l’affichage, cela donne une apparence bizarre montrant quelque chose comme "-0.0".
Pour la méthode int, les nombres négatifs peuvent changer le résultat souhaité (bien que certains arguments puissent être définis, ils sont corrects).
Le int + 0.5
pose de vrais problèmes avec les nombres négatifs, à moins que vous ne vouliez que cela fonctionne ainsi, mais j'imagine que la plupart des gens ne le font pas. -0,9 devrait probablement arrondir à -1 et non pas 0. Si vous savez que vous voulez que le négatif soit un plafond plutôt qu'un sol, vous pouvez le faire en une ligne, sinon, vous pouvez utiliser la méthode int avec un mineur modification (cela ne fonctionne évidemment que pour récupérer des nombres entiers:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
Ma solution pour sprintf
if ($value =~ m/\d\..*5$/){
$format =~ /.*(\d)f$/;
if (defined $1){
my $coef = "0." . "0" x $1 . "05";
$value = $value + $coef;
}
}
$value = sprintf( "$format", $value );
Si vous souhaitez uniquement obtenir une valeur entière dans un nombre entier à virgule flottante (c'est-à-dire 12347.9999 ou 54321.0001), cette approche (empruntée et modifiée ci-dessus) fera l'affaire:
my $rounded = floor($float + 0.1);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'