回答:
の出力 perldoc -q round
Perlにはround()関数がありますか?ceil()とfloor()はどうですか?トリガー関数?がに
int()
向かって切り捨てられるだけであることを覚えておいてください0
。特定の桁数に丸める場合、sprintf()
またはprintf()
通常は最も簡単なルートです。
printf("%.3f", 3.1415926535); # prints 3.142
POSIX
モジュール(標準Perl配布の一部)を実装しceil()
、floor()
および他の数学的及び三角関数の数。
use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
5.000から5.003のperlsでは、
Math::Complex
モジュールで三角法が行われました。5.004では、Math::Trig
モジュール(標準Perl配布の一部)が三角関数を実装します。内部的にはMath::Complex
モジュールを使用し、2の逆サインなど、一部の関数は実軸から複素平面にブレークアウトできます。金融アプリケーションでの丸めは深刻な影響を与える可能性があり、使用される丸め方法は正確に指定する必要があります。これらの場合、Perlが使用しているシステム丸めを信頼するのではなく、代わりに必要な丸め関数を実装することは価値があります。
理由を確認するには、中間点交替でまだ問題が発生することに注意してください。
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
Perlを責めないでください。これはCと同じです。IEEEはこれを実行する必要があると言っています。絶対値が整数
2**31
(32ビットマシン上)であるPerlの数値は、数学的な整数とほとんど同じように機能します。その他の数値は保証されません。
printf
結果を変数にしたい場合は使用しないでください。使用してくださいsprintf
。これにより、デバッグ時間を節約できます:-P
int()
PDLで使用できますか?
中間点などに関する複雑な回答には同意しませんが、より一般的な(そして些細な)ユースケースについては、次のようになります。
my $rounded = int($float + 0.5);
更新
$float
がマイナスになる可能性がある場合は、次のバリエーションで正しい結果が得られます。
my $rounded = int($float + $float/abs($float*2 || 1));
この計算では、-1.4は-1に丸められ、-1.6は-2に丸められ、ゼロは爆発しません。
Math :: Roundのようなモジュールを使用できます。
use Math::Round;
my $rounded = round( $float );
または、大雑把な方法でそれを行うことができます:
my $rounded = sprintf "%.0f", $float;
printfまたはsprintfを使用することに決めた場合、それらは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
perldoc / perlfaqを参照してください。
int()
単に0に向かって切り捨てられることを忘れないでください。特定の桁数に丸める場合、sprintf()
またはprintf()
通常は最も簡単なルートです。printf("%.3f",3.1415926535); # prints 3.142
POSIX
モジュール(標準Perl配布の一部)を実装しceil()
、floor()
および他の数学的及び三角関数の数。use POSIX; $ceil = ceil(3.5); # 4 $floor = floor(3.5); # 3
5.000から5.003のperlsでは、
Math::Complex
モジュールで三角法が行われました。5.004では、
Math::Trig
モジュール(標準のPerlディストリビューションの一部)>三角関数を実装します。内部的には
Math::Complex
モジュールを使用し、2の逆サインなど、一部の関数は実軸から複素平面にブレークアウトできます。金融アプリケーションでの丸めは深刻な影響を与える可能性があり、使用される丸め方法は正確に指定する必要があります。これらの場合、Perlが使用しているシステム丸めを信頼するのではなく、代わりに必要な丸め関数を実装することは価値があります。
理由を確認するには、中間点交替でまだ問題が発生することに注意してください。
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
Perlを責めないでください。これはCと同じです。IEEEはこれを実行する必要があると言っています。絶対値が2 ** 31(32ビットマシン上)未満の整数であるPerl番号は、数学的な整数とほとんど同じように機能します。その他の数値は保証されません。
外部モジュールは必要ありません。
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
print "\n";
}
私はあなたの要点を逃しているかもしれませんが、これは同じ仕事をするためのはるかにきれいな方法だと思いました。
これは、要素内のすべての正の数を調べ、その数と丸めた整数を、指定した形式で出力することです。このコードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。INT($ _)は、基本的に切り捨て番号ので($ -int($))は、小数点以下をキャプチャします。小数が(定義により)厳密に0.5未満の場合は、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
以下は、値を合計する5つの異なる方法のサンプルです。1つ目は、合計を実行する素朴な方法です(失敗します)。2番目はを使用しようとしますがsprintf()
、失敗します。sprintf()
最後の2つ(4番目と5番目)の使用中に、3番目は正常に使用されます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
への依存関係を削除するためにfloor($value + 0.5)
で置き換えることができることに注意してください。int($value + 0.5)
POSIX
負の数は、人々が注意する必要があるいくつかの癖を追加できます。
printf
スタイルのアプローチでは正しい数が得られますが、奇妙な表示になる場合があります。この方法(私の意見では、愚かに)が、-
それをすべきか、すべきでないかに関わらず、サインを入れることを発見しました。たとえば、小数点以下1桁に丸められた-0.01は、単に0ではなく-0.0を返します。printf
スタイルアプローチを実行する予定で、小数点が不要であることがわかっている場合は、使用%d
せずに使用%f
します(小数点が必要な場合は、表示が不安定になります)。
それは正しく、数学的には大した問題ではありませんが、表示の場合は「-0.0」のような奇妙な表示になります。
intメソッドの場合、結果として負の数を使用すると、必要な値が変わる可能性があります(ただし、引数を正しいものにすることができるいくつかの引数があります)。
int + 0.5
あなたはそれがそのように動作する場合を除き、陰性の数字で、実際の問題の原因となるが、私はほとんどの人がいない想像します。-0.9はおそらく0ではなく-1に丸める必要があります。負の値を床ではなく天井にしたい場合は、ワンライナーで実行できます。それ以外の場合は、intメソッドをマイナーで使用することができます。変更(これは明らかに整数を取得するためにのみ機能します:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
浮動小数点数全体から整数値を取得することだけに関心がある場合(つまり、12347.9999または54321.0001)、このアプローチ(上から借りて変更)でうまくいきます。
my $rounded = floor($float + 0.1);
数値を丸める方法に関するドキュメントを大量に読む場合、多くの専門家は独自の丸めルーチンを作成することを提案します。これは、言語で提供されている「缶詰」バージョンが十分に正確でないか、エラーが含まれている可能性があるためです。しかし、彼らは、1、2、または3だけでなく、多くの小数点以下の桁数を話していると思います。それを念頭に置いて、ここに私の解決策があります(私の要求はドルを表示する必要があるため、要求どおりには正確ではありませんが、プロセスには大きな違いはありません)。
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]++; } } }
それはですので: if ($digit1 >= 5) { $digit1 = 0; $cost[0]++; }
そして、ちょうどreturn commafied($cost[0]);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'