問題: 数値を最も近い .01 に切り捨てたい。
これは私が思いついた解決策です:
return int($_[0]*100)/100;
デバッガーでこの小さな宝石を偶然分離するまでは問題ないようです。
DB<2> p $_[0]
16.78
DB<3> p $_[0] * 100
1678
DB<4> p int($_[0] * 100)
1677
DB<5> p int(16.78 * 100)
1678
1 つの重要な注意点は、$_[0] はもともとあるテキストからスクレイピングされたことです。Perl はテキスト "16.78" を 16.78 からイプシロンを引いたものとして表しているようですが、それを "16.78" として出力しているようです。
PS POSIX::floor も同じように失敗します。
表示するには:
ああ、でも入力が 16.7799 だったら?
use strict;
use warnings;
my $float = 16.7799;
my $not_rounded = int($float*100)/100;
my $sprintf_rounded = sprintf "%.2f", $float;
my $int_rounded = int( ($float+0.005) * 100 )/100;
print "first method: " . $not_rounded ."\n"; # => 16.77
print "second method: " . $sprintf_rounded ."\n"; # => 16.78
print "third method: " . $int_rounded . "\n"; # => 16.78
結果は 16.77 になるはずですが、次のようになります。
$ perl test.pl
first method: 16.77
second method: 16.78
third method: 16.78
言い換えれば、小数点以下を切り捨て、浮動小数点数で表現できる整数倍に近い入力の場合は切り上げ、小数点以下は切り上げます。
たとえば、入力が 16.77999999999999758415 で、それが 0.01 (16.78) の最も近い倍数の最も正確な表現であり、その数値よりも小さい場合は、最も近い 0.01 に切り上げます。それ以外の場合は、最も近い 0.01 に切り下げます。
Perl が浮動小数点数として解釈できるテキストから削り取られたスカラーを設定するとき、可能な限り正確な表現を選択するという仮定の下で動作していることに注意してください。おそらく合理的です。