Perlでどのように浮動小数点数を丸めますか?
-
05-07-2019 - |
質問
10進数(浮動小数点)を最も近い整数に丸めるにはどうすればよいですか?
e.g。
1.2 = 1
1.7 = 2
解決
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のPerlでは、三角法は
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ビットマシン)は、数学的な整数のように機能します。 他の数値は保証されません。
他のヒント
中間点などに関する複雑な回答には同意しませんが、より一般的な(そしておそらくはささいな)ユースケースについては
my $ rounded = int($ float + 0.5);
更新
$ float
がマイナスになる可能性がある場合、次のバリエーションで正しい結果が生成されます。
my $ rounded = int($ float + $ float / abs($ float * 2 || 1));
この計算では、-1.4は-1に丸められ、-1.6は-2に丸められ、ゼロは爆発しません。
use Math::Round;
my $rounded = round( $float );
または粗雑な方法でそれを行うことができます:
my $rounded = sprintf "%.0f", $float;
printfまたはsprintfを使用する場合は、半分から偶数までメソッド。
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
Perl 5.000から5.003では、三角法は
Math :: Complex
モジュールで行われました。5.004では、
Math :: Trig
モジュール(標準Perlディストリビューションの一部)&gt;三角関数を実装します。内部的には
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未満の整数であるPerl番号(on 32ビットマシン)は、数学的な整数のように機能します。 その他の数値は保証されていません。
外部モジュールは必要ありません。
$x[0] = 1.2;
$x[1] = 1.7;
foreach (@x){
print 外部モジュールは必要ありません。
<*>
あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。
これは、要素内のすべての正数を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に数値を切り捨てするため、($ -int($ ))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
.' = '.( ( (外部モジュールは必要ありません。
<*>
あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。
これは、要素内のすべての正数を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に数値を切り捨てするため、($ -int($ ))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
-int(外部モジュールは必要ありません。
<*>
あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。
これは、要素内のすべての正数を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に数値を切り捨てするため、($ -int($ ))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
))<0.5) ? int(外部モジュールは必要ありません。
<*>
あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。
これは、要素内のすべての正数を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に数値を切り捨てするため、($ -int($ ))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
) : int(外部モジュールは必要ありません。
<*>
あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。
これは、要素内のすべての正数を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に数値を切り捨てするため、($ -int($ ))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
)+1 );
print "\n";
}
あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。
これは、要素内のすべての正数を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に数値を切り捨てするため、($ -int($ ))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。
以下は、正または負の数を指定された小数位に丸めます:
sub round ()
{
my ($x, $pow10) = @_;
my $a = 10 ** $pow10;
return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}
以下は、値を合計する5つの異なる方法のサンプルです。最初の方法は、単純な方法で加算を実行します(そして失敗します)。 2番目は sprintf()
を使用しようとしますが、これも失敗します。 3番目は sprintf()
を正常に使用し、最後の2つ(4番目と5番目)は 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
スタイルのアプローチを実行する場合、小数点が必要ないことがわかっている場合は、を使用します
(小数が必要な場合は、ディスプレイが不安定になります)。%f
ではなく%d
それは正しいが、数学にとっては大した問題ではないが、表示のために「-0.0」のようなものを表示するだけで奇妙に見える。
intメソッドの場合、負の数は結果として必要なものを変更する可能性があります(ただし、いくつかの引数は正しいものにすることができます)。
int + 0.5
は、負の数で実際の問題を引き起こしますが、そのように動作させたい場合を除きますが、ほとんどの人はそうではないと思います。 -0.9は、おそらく0ではなく-1に丸める必要があります。ネガティブをフロアではなく天井にしたい場合は、1ライナーで行うことができます。そうでない場合は、マイナーでintメソッドを使用することができます変更(これは明らかに整数を戻すためにのみ機能します:
my $var = -9.1;
my $tmpRounded = int( abs($var) + 0.5));
my $finalRounded = $var >= 0 ? 0 + $tmpRounded : 0 - $tmpRounded;
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 );
浮動小数点数全体(つまり、12347.9999または54321.0001)から整数値を取得することにのみ関心がある場合、このアプローチ(上記から借用および変更)でトリックが行われます:
my $rounded = floor($float + 0.1);
cat table |
perl -ne '/\d+\s+(\d+)\s+(\S+)/ && print "".**int**(log($1)/log(2))."\t$2\n";'