Comment puis-je arrondir un nombre décimal (virgule flottante) à l'entier le plus proche?
par exemple.
1.2 = 1
1.7 = 2
Sortie de perldoc -q round
Est-ce que Perl a une fonction round ()? Qu'en est-il de ceil () et de floor ()? Fonctions Trig?Rappelez-vous que
int()
ne fait que tronquer vers _0
_. Pour arrondir à un certain nombre de chiffres,sprintf()
ouprintf()
est généralement la route la plus simple._printf("%.3f", 3.1415926535); # prints 3.142
_Le module
POSIX
(composant de la distribution Perl standard) implémenteceil()
,floor()
et un certain nombre d'autres fonctions mathématiques et trigonométriques._use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
_Dans 5.000 à 5.003 perls, la trigonométrie a été effectuée dans le module
Math::Complex
. Avec 5.004, le moduleMath::Trig
(composant de la distribution Perl standard) implémente les fonctions trigonométriques. En interne, il utilise le moduleMath::Complex
et certaines fonctions peuvent sortir de l’axe réel dans le plan complexe, par exemple le sinus inverse de 2.Arrondir des 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 cas, il vaut probablement mieux ne pas se fier au système d'arrondi utilisé par Perl, mais mettre en œuvre la fonction d'arrondi dont vous avez besoin.
Pour voir pourquoi, remarquez que vous aurez toujours un problème d'alternance à mi-chemin:
_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 qu'en C. L'IEEE dit que nous devons faire cela. Les nombres Perl dont les valeurs absolues sont des entiers inférieurs à _
2**31
_ (sur les machines 32 bits) fonctionneront plus ou moins comme des entiers mathématiques. Les autres numéros ne sont pas garantis.
Bien que vous ne soyez 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):
my $rounded = int($float + 0.5);
UPDATE
S'il est possible que votre $float
soit négatif, la variation suivante produira le résultat correct:
my $rounded = int($float + $float/abs($float*2 || 1));
Avec ce calcul, -1,4 est arrondi à -1, et -1,6 à -2 et zéro n'explosera pas.
Vous pouvez soit utiliser un module comme Math :: Round :
use Math::Round;
my $rounded = round( $float );
Ou vous pouvez le faire de manière grossière:
my $rounded = sprintf "%.0f", $float;
Si vous décidez d'utiliser printf ou sprintf, notez qu'ils utilisent la méthode arrondir la moitié au même .
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 :
Rappelez-vous que
int()
ne fait que tronquer vers 0. Pour arrondir à un certain nombre de chiffres,sprintf()
ouprintf()
est généralement le chemin le plus simple.printf("%.3f",3.1415926535); # prints 3.142
Le module
POSIX
(composant de la distribution Perl standard) implémenteceil()
,floor()
et un certain nombre d'autres fonctions mathématiques et trigonométriques.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Dans 5.000 à 5.003 perls, la trigonométrie a été effectuée dans le module
Math::Complex
.Avec 5.004, le module
Math::Trig
(qui fait partie de la distribution Perl standard)> implémente les fonctions trigonométriques.En interne, il utilise le module
Math::Complex
et certaines fonctions peuvent sortir de l’axe réel dans le plan complexe, par exemple le sinus inverse de 2.Arrondir des 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 cas, il vaut probablement mieux ne pas se fier au système d'arrondi utilisé par Perl, mais mettre en œuvre la fonction d'arrondi dont vous avez besoin.
Pour voir pourquoi, remarquez que vous aurez toujours un problème d'alternance à mi-chemin:
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 qu'en C. L'IEEE dit que nous devons faire cela. Les nombres Perl dont les valeurs absolues sont des entiers inférieurs à 2 ** 31 (sur les 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 $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
print "\n";
}
J'ignore peut-être ce que vous voulez dire, mais j’ai pensé que c’était une façon beaucoup plus propre de faire le même travail.
Cela consiste à parcourir chaque nombre positif dans l'élément, à 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 nombres décimaux. int ($ _) fondamentalement arrondi le nombre so ($ - int ($)) capture les nombres décimaux. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre. Sinon, arrondissez en ajoutant 1.
Les nombres négatifs peuvent ajouter certaines bizarreries que les gens doivent connaître.
Les approches de style printf
- nous donnent des nombres corrects, mais elles peuvent donner des affichages bizarres. Nous avons découvert que cette méthode (à mon avis, bêtement) met 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 insignifiant).
Bien que ce soit correct et pour les mathématiques, ce n’est pas grave, mais pour l’affichage, cela semble bizarre, montrant quelque chose comme "-0.0".
Pour la méthode int, les nombres négatifs peuvent modifier 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;
Voici un exemple 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 floor($value + 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($value + 0.5)
peut être remplacé par int($value + 0.5)
pour supprimer la dépendance sur POSIX
.
Les éléments suivants arrondiront 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);
}
Si vous souhaitez uniquement obtenir une valeur entière sur 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);
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 );