0

問題: 数値を最も近い .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 が浮動小数点数として解釈できるテキストから削り取られたスカラーを設定するとき、可能な限り正確な表現を選択するという仮定の下で動作していることに注意してください。おそらく合理的です。

4

4 に答える 4

2

前述のように、浮動小数点演算を使用する場合、奇妙なアーティファクトを考慮する必要があります。代わりに機能する丸めの方法をいくつか示します。

use strict;
use warnings;

my $float = 16.77999999999999758415
my $not_rounded     = int($float*100)/100;
my $sprintf_rounded = sprintf "%.2f", $float;
my $int_rounded     = int( ($float+0.005) * 100 )/100;

say $not_rounded;     # => 16.77
say $sprintf_rounded; # => 16.78
say $int_rounded;     # => 16.78
于 2013-07-17T17:51:20.083 に答える
1

このように、不合理なものをバイナリで出力することにより、内部浮動小数点表現の正確さを知ることができます。

printf "%.30f\n", 4/9;

そして私は得る

0.444444444444444420000000000000

したがって、私のフロートは有効数字約 16 桁まで正確です。

これで、16 桁目に 5 を追加することで、適切に表現された最も近い数値に丸めることができるので、ポイントの前の 2 桁を考慮して、

sub trunc {
  my $x = shift() + 5E-14;
  int($x * 100) / 100.0;
}

print trunc(16.77999999999999758415);

出力

16.78

もちろん、Perl の float の精度の限界を押し上げる必要はありません。入力データの精度の半分を追加するだけで、正しい結果が得られます。

于 2013-07-17T20:36:46.687 に答える
1
    #!usr/bin/perl -w
    use strict;
    $\ = "\n";
    print "Enter the value and the roundto [Ex:roundto nearest 100 or 1000 etc] ";
    chomp (my $value = <STDIN>);
    chomp (my $digit = <STDIN>);
    my $round;
    $round = int( ($value+ $digit /2)/ $digit )* $digit;
    print "After rounding: $round";
于 2013-07-17T22:12:15.563 に答える
0

これが解決策の 1 つのパスです。きっと他にもっと優れたものがあるはずです。

sub regex_round_down {
    my $var = shift;
    $var =~ s/^\./0./;
    $var =~ s/^(\d+(\.\d{1,2})?).*$/$1/;
    return $var;
}
于 2013-07-17T19:28:51.080 に答える