Antworten:
Ausgabe von perldoc -q round
Hat Perl eine round () Funktion? Was ist mit Decke () und Boden ()? Triggerfunktionen?Denken Sie daran, dass
int()
nur in Richtung abgeschnitten0
. Zum Runden auf eine bestimmte Anzahl von Stellensprintf()
oderprintf()
ist in der Regel die einfachste Route.
printf("%.3f", 3.1415926535); # prints 3.142
Das
POSIX
Modul (Teil der Standard - Perl - Verteilung) implementiertceil()
,floor()
und eine Reihe von anderen mathematischen und trigonometrischen Funktionen.
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Bei 5.000 bis 5.003 Perlen wurde im
Math::Complex
Modul eine Trigonometrie durchgeführt . Mit 5.004Math::Trig
implementiert das Modul (Teil der Standard-Perl-Distribution) die trigonometrischen Funktionen. Intern wird dasMath::Complex
Modul verwendet und einige Funktionen können von der realen Achse in die komplexe Ebene ausbrechen, beispielsweise der inverse Sinus von 2.Rundungen in Finanzanwendungen können schwerwiegende Folgen haben, und die verwendete Rundungsmethode sollte genau angegeben werden. In diesen Fällen lohnt es sich wahrscheinlich, nicht der von Perl verwendeten Systemrundung zu vertrauen, sondern stattdessen die von Ihnen benötigte Rundungsfunktion selbst zu implementieren.
Um zu sehen, warum, beachten Sie, dass Sie immer noch ein Problem mit dem Wechsel auf halber Strecke haben:
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
Beschuldige Perl nicht. Es ist das gleiche wie in C. IEEE sagt, dass wir dies tun müssen. Perl-Zahlen, deren absolute Werte Ganzzahlen unter
2**31
(auf 32-Bit-Computern) sind, funktionieren ähnlich wie mathematische Ganzzahlen. Andere Nummern sind nicht garantiert.
printf
Sie nicht zu verwenden, wenn Sie das Ergebnis in einer Variablen wollen, verwenden Sie sprintf
... hoffe, dies spart Ihnen einige Debugging-Zeit :-P
int()
auf PDLs verwenden?
Obwohl Sie den komplexen Antworten zu Halbwertszeiten usw. nicht widersprechen, gilt für den allgemeineren (und möglicherweise trivialeren) Anwendungsfall Folgendes:
my $rounded = int($float + 0.5);
AKTUALISIEREN
Wenn es möglich ist, dass Sie $float
negativ sind, führt die folgende Variation zum richtigen Ergebnis:
my $rounded = int($float + $float/abs($float*2 || 1));
Bei dieser Berechnung wird -1,4 auf -1 und -1,6 auf -2 gerundet, und Null explodiert nicht.
Sie können entweder ein Modul wie Math :: Round verwenden :
use Math::Round;
my $rounded = round( $float );
Oder Sie können es auf grobe Weise tun:
my $rounded = sprintf "%.0f", $float;
Wenn Sie sich für printf oder sprintf entscheiden, beachten Sie, dass die Methode Round Round to Even verwendet wird.
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
Siehe perldoc / perlfaq :
Denken Sie daran, dass dies
int()
nur in Richtung 0 abgeschnitten wird. Zum Runden auf eine bestimmte Anzahl von Ziffernsprintf()
oderprintf()
normalerweise die einfachste Route.printf("%.3f",3.1415926535); # prints 3.142
Das
POSIX
Modul (Teil der Standard - Perl - Verteilung) implementiertceil()
,floor()
und eine Reihe von anderen mathematischen und trigonometrischen Funktionen.use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
Bei 5.000 bis 5.003 Perlen wurde im
Math::Complex
Modul eine Trigonometrie durchgeführt .Mit 5.004
Math::Trig
implementiert das Modul (Teil der Standard-Perl-Distribution)> die trigonometrischen Funktionen.Intern wird das
Math::Complex
Modul verwendet und einige Funktionen können von der realen Achse in die komplexe Ebene ausbrechen, beispielsweise der inverse Sinus von 2.Rundungen in Finanzanwendungen können schwerwiegende Folgen haben, und die verwendete Rundungsmethode sollte genau angegeben werden. In diesen Fällen lohnt es sich wahrscheinlich, nicht der von Perl verwendeten Systemrundung zu vertrauen, sondern stattdessen die von Ihnen benötigte Rundungsfunktion selbst zu implementieren.
Um zu sehen, warum, beachten Sie, dass Sie immer noch ein Problem mit dem Wechsel auf halber Strecke haben:
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
Beschuldige Perl nicht. Es ist das gleiche wie in C. IEEE sagt, wir müssen dies tun. Perl-Zahlen, deren absolute Werte Ganzzahlen unter 2 ** 31 sind (auf 32-Bit-Computern), funktionieren ähnlich wie mathematische Ganzzahlen. Andere Nummern sind nicht garantiert.
Sie benötigen kein externes Modul.
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
print "\n";
}
Ich vermisse vielleicht Ihren Standpunkt, aber ich dachte, dies wäre eine viel sauberere Art, den gleichen Job zu machen.
Dazu gehen Sie durch jede positive Zahl im Element, drucken die Zahl und die gerundete Ganzzahl in dem von Ihnen genannten Format. Der Code verkettet die jeweilige gerundete positive Ganzzahl nur basierend auf den Dezimalstellen. int ($ _) rundet die Zahl grundsätzlich ab, sodass ($ -int ($ )) die Dezimalstellen erfasst. Wenn die Dezimalstellen (per Definition) streng kleiner als 0,5 sind, runden Sie die Zahl ab. Wenn nicht, runden Sie mit 1 auf.
Im Folgenden finden Sie eine Auswahl von fünf verschiedenen Möglichkeiten zum Summieren von Werten. Der erste ist ein naiver Weg, um die Summierung durchzuführen (und schlägt fehl). Der zweite Versuch zu verwendensprintf()
, aber es schlägt auch fehl. Der dritte wird sprintf()
erfolgreich verwendet, während die letzten beiden (4. und 5.) verwendet werden 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
Beachten Sie, dass floor($value + 0.5)
durch ersetzt werden kann int($value + 0.5)
, um die Abhängigkeit von zu entfernen POSIX
.
Negative Zahlen können einige Macken hinzufügen, die die Leute beachten müssen.
printf
Ansätze im Stil geben uns korrekte Zahlen, aber sie können zu ungeraden Anzeigen führen. Wir haben herausgefunden, dass diese Methode (meiner Meinung nach dumm) ein -
Zeichen setzt , ob sie sollte oder nicht. Zum Beispiel gibt -0,01 auf eine Dezimalstelle gerundet eine -0,0 statt nur 0 zurück. Wenn Sie den Stilansatz ausführen printf
möchten und wissen, dass Sie keine Dezimalstelle möchten, verwenden Sie %d
und nicht %f
(wenn Sie Dezimalstellen benötigen, ist es, wenn die Anzeige wird wackelig).
Während es korrekt ist und für Mathematik keine große Sache ist, sieht es für die Anzeige nur seltsam aus, wenn man so etwas wie "-0.0" zeigt.
Bei der int-Methode können negative Zahlen das ändern, was Sie als Ergebnis wollen (obwohl einige Argumente vorgebracht werden können, sind sie korrekt).
Das int + 0.5
verursacht echte Probleme mit -negativen Zahlen, es sei denn, Sie möchten, dass es so funktioniert, aber ich kann mir vorstellen, dass die meisten Menschen dies nicht tun. -0,9 sollte wahrscheinlich auf -1 und nicht auf 0 runden. Wenn Sie wissen, dass Negativ eher eine Decke als ein Boden sein soll, können Sie dies einzeilig tun. Andernfalls möchten Sie möglicherweise die int-Methode mit einem Moll verwenden Modifikation (dies funktioniert offensichtlich nur, um ganze Zahlen zurückzugewinnen:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
Wenn Sie nur einen ganzzahligen Wert aus einer ganzen Gleitkommazahl (dh 12347.9999 oder 54321.0001) erhalten möchten, reicht dieser Ansatz (von oben entlehnt und geändert) aus:
my $rounded = floor($float + 0.1);
Viele Experten empfehlen, eigene Rundungsroutinen zu schreiben, da die mit Ihrer Sprache gelieferte "Dosen" -Version möglicherweise nicht präzise genug ist oder Fehler enthält. Ich stelle mir jedoch vor, dass sie viele Dezimalstellen sprechen, nicht nur eine, zwei oder drei. In diesem Sinne ist hier meine Lösung (obwohl nicht genau so gefordert, wie es meine Bedürfnisse sind, Dollars anzuzeigen - der Prozess ist jedoch nicht viel anders).
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]++; } } }
So ist es: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; }
dann nurreturn commafied($cost[0]);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'