Réponses:
Sortie de perldoc -q round
Perl a-t-il une fonction round ()? Qu'en est-il de ceil () et floor ()? Fonctions de déclenchement?Rappelez-vous que cela
int()
tronque simplement vers0
. Pour arrondir à un certain nombre de chiffres,sprintf()
ouprintf()
est généralement l'itinéraire le plus simple.
printf("%.3f", 3.1415926535); # prints 3.142
Le
POSIX
module (partie de la distribution standard de Perl) met en œuvreceil()
,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
Math::Complex
module. Avec 5.004, leMath::Trig
module (qui fait partie de la distribution standard de Perl) implémente les fonctions trigonométriques. En interne, il utilise leMath::Complex
module et certaines fonctions peuvent sortir de l'axe réel dans le plan complexe, par exemple le sinus inverse de 2.L'arrondi dans les applications financières peut avoir de graves implications et la méthode d'arrondi utilisée doit être spécifiée avec précision. Dans ces cas, il vaut probablement mieux ne pas faire confiance à l'arrondi système utilisé par Perl, mais plutôt implémenter la fonction d'arrondi dont vous avez besoin.
Pour voir pourquoi, remarquez que vous aurez toujours un problème sur l'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 que dans C. IEEE dit que nous devons le faire. Les nombres Perl dont les valeurs absolues sont des entiers inférieurs
2**31
(sur les machines 32 bits) fonctionneront à peu près comme des entiers mathématiques. Les autres numéros ne sont pas garantis.
printf
si vous voulez le résultat dans une variable, utilisez sprintf
... j'espère que cela vous fera gagner du temps de débogage :-P
int()
sur les PDL?
Sans être en désaccord avec les réponses complexes sur les notes à mi-chemin et ainsi de suite, pour le cas d'utilisation le plus courant (et peut-être trivial):
my $rounded = int($float + 0.5);
METTRE À JOUR
S'il est possible que vous $float
soyez 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 Round half to even .
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()
tronque simplement vers 0. Pour arrondir à un certain nombre de chiffres,sprintf()
ouprintf()
est généralement l'itinéraire le plus simple.printf("%.3f",3.1415926535); # prints 3.142
Le
POSIX
module (partie de la distribution standard de Perl) met en œuvreceil()
,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
Math::Complex
module.Avec 5.004, le
Math::Trig
module (qui fait partie de la distribution Perl standard)> implémente les fonctions trigonométriques.En interne, il utilise le
Math::Complex
module et certaines fonctions peuvent sortir de l'axe réel dans le plan complexe, par exemple le sinus inverse de 2.L'arrondi dans les applications financières peut avoir de graves implications et la méthode d'arrondi utilisée doit être spécifiée avec précision. Dans ces cas, il vaut probablement mieux ne pas faire confiance à l'arrondi système utilisé par Perl, mais plutôt implémenter la fonction d'arrondi dont vous avez besoin.
Pour voir pourquoi, remarquez que vous aurez toujours un problème sur l'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 que dans C. IEEE dit que nous devons le faire. Les nombres Perl dont les valeurs absolues sont des entiers inférieurs à 2 ** 31 (sur les machines 32 bits) fonctionneront à peu près 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";
}
Votre argument me manque peut-être, mais je pensais que c'était une manière beaucoup plus propre de faire le même travail.
Cela permet de parcourir chaque nombre positif de l'élément, d'imprimer le nombre et l'entier arrondi dans le format que vous avez mentionné. Le code concatène un entier positif arrondi respectif uniquement en fonction des décimales. int ($ _) essentiellement rond vers le bas le nombre si ($ -INT ($ )) capture les décimales. Si les décimales sont (par définition) strictement inférieures à 0,5, arrondissez le nombre à la baisse. Sinon, arrondissez en ajoutant 1.
Voici un exemple de cinq façons différentes de sommer les valeurs. Le premier est une manière naïve 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 (4e et 5e) 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 nombres négatifs peuvent ajouter des bizarreries dont les gens doivent être conscients.
printf
-Les approches de style nous donnent des nombres corrects, mais elles peuvent entraîner des affichages étranges. Nous avons découvert que cette méthode (à mon avis, bêtement) met un -
signe si oui ou non elle devrait ou non. Par exemple, -0,01 arrondi à une décimale renvoie un -0,0, plutôt que juste 0. Si vous allez faire l' printf
approche de style, et que vous savez que vous ne voulez pas de décimale, utilisez %d
et non %f
(lorsque vous avez besoin de décimales, c'est quand le l'affichage devient bancal).
Bien que ce soit correct et pour les mathématiques, ce n'est pas un problème, pour l'affichage, cela semble bizarre en montrant quelque chose comme "-0.0".
Pour la méthode int, les nombres négatifs peuvent changer ce que vous voulez en conséquence (bien que certains arguments puissent être avancés, ils sont corrects).
La int + 0.5
cause des problèmes réels avec des numéros séronégatifs, sauf si vous voulez que cela fonctionne de cette façon, mais j'imagine que la plupart des gens ne le font pas. -0,9 devrait probablement arrondir à -1, pas à 0. Si vous savez que vous voulez que le négatif soit un plafond plutôt qu'un plancher, vous pouvez le faire en une seule ligne, sinon, vous voudrez peut-être 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;
Si vous ne souhaitez obtenir qu'une valeur entière à partir d'un nombre entier à virgule flottante (c'est-à-dire 12347,9999 ou 54321,0001), cette approche (empruntée et modifiée par le haut) fera l'affaire:
my $rounded = floor($float + 0.1);
beaucoup de documentation de lecture sur la façon d'arrondir les nombres, de nombreux experts suggèrent d'écrire vos propres routines d'arrondi, car la version «en conserve» fournie avec votre langue peut ne pas être assez précise ou contenir des erreurs. J'imagine, cependant, qu'ils parlent de nombreuses décimales, pas seulement un, deux ou trois. dans cet esprit, voici ma solution (bien que pas EXACTEMENT aussi demandé que mes besoins sont d'afficher des dollars - le processus n'est pas très différent, cependant).
sub asDollars($) {
my ($cost) = @_;
my $rv = 0;
my $negative = 0;
if ($cost =~ /^-/) {
$negative = 1;
$cost =~ s/^-//;
}
my @cost = split(/\./, $cost);
# let's get the first 3 digits of $cost[1]
my ($digit1, $digit2, $digit3) = split("", $cost[1]);
# now, is $digit3 >= 5?
# if yes, plus one to $digit2.
# is $digit2 > 9 now?
# if yes, $digit2 = 0, $digit1++
# is $digit1 > 9 now??
# if yes, $digit1 = 0, $cost[0]++
if ($digit3 >= 5) {
$digit3 = 0;
$digit2++;
if ($digit2 > 9) {
$digit2 = 0;
$digit1++;
if ($digit1 > 9) {
$digit1 = 0;
$cost[0]++;
}
}
}
$cost[1] = $digit1 . $digit2;
if ($digit1 ne "0" and $cost[1] < 10) { $cost[1] .= "0"; }
# and pretty up the left of decimal
if ($cost[0] > 999) { $cost[0] = commafied($cost[0]); }
$rv = join(".", @cost);
if ($negative) { $rv = "-" . $rv; }
return $rv;
}
sub commafied($) {
#*
# to insert commas before every 3rd number (from the right)
# positive or negative numbers
#*
my ($num) = @_; # the number to insert commas into!
my $negative = 0;
if ($num =~ /^-/) {
$negative = 1;
$num =~ s/^-//;
}
$num =~ s/^(0)*//; # strip LEADING zeros from given number!
$num =~ s/0/-/g; # convert zeros to dashes because ... computers!
if ($num) {
my @digits = reverse split("", $num);
$num = "";
for (my $i = 0; $i < @digits; $i += 3) {
$num .= $digits[$i];
if ($digits[$i+1]) { $num .= $digits[$i+1]; }
if ($digits[$i+2]) { $num .= $digits[$i+2]; }
if ($i < (@digits - 3)) { $num .= ","; }
if ($i >= @digits) { last; }
}
#$num =~ s/,$//;
$num = join("", reverse split("", $num));
$num =~ s/-/0/g;
}
if ($negative) { $num = "-" . $num; }
return $num; # a number with commas added
#usage: my $prettyNum = commafied(1234567890);
}
if ($digit3 >= 5) { $digit3 = 0; $digit2++; if ($digit2 > 9) { $digit2 = 0; $digit1++; if ($digit1 > 9) { $digit1 = 0; $cost[0]++; } } }
donc c'est: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; }
alors justereturn commafied($cost[0]);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'