web-dev-qa-db-ja.com

Perlでどのように浮動小数点数を丸めますか?

10進数(浮動小数点)を最も近い整数に丸めるにはどうすればよいですか?

例えば.

1.2 = 1
1.7 = 2
167
Ranguard

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 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ビットマシン上)のPerl数値は、数学的な整数とほとんど同じように機能します。他の数値は保証されません。

191
Vinko Vrsalovic

より一般的な(そしておそらく些細な)ユースケースのために、中間点などに関する複雑な答えに反対しませんが:

my $rounded = int($float + 0.5);

UPDATE

$floatが負になる可能性がある場合、次のバリエーションにより正しい結果が生成されます。

my $rounded = int($float + $float/abs($float*2 || 1));

この計算では、-1.4は-1に丸められ、-1.6は-2に丸められ、ゼロは爆発しません。

127
RET

Math :: Round :のようなモジュールを使用できます

use Math::Round;
my $rounded = round( $float );

または、大まかな方法​​でそれを行うことができます:

my $rounded = sprintf "%.0f", $float;
71
EvdB

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
45
Kyle

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ディストリビューションの一部)>は三角関数を実装しています。

内部的には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番号は、数学的な整数とほとんど同じように機能します。他の数値は保証されません。

8
Kent Fredric

外部モジュールは必要ありません。

$x[0] = 1.2;
$x[1] = 1.7;

foreach (@x){
  print $_.' = '.( ( ($_-int($_))<0.5) ? int($_) : int($_)+1 );
  print "\n";
}

あなたの意見が欠けているかもしれませんが、これは同じ仕事をするためのずっときれいな方法だと思いました。

これは、要素内のすべての正の数値を調べて、指定した形式で数値と丸められた整数を出力することです。コードは、小数点以下のみに基づいて、それぞれの丸められた正の整数を連結します。 int($ _)は基本的に切り捨て数値なので、($ -int($))は小数をキャプチャします。小数が(定義上)厳密に0.5未満の場合、数値を切り捨てます。そうでない場合は、1を追加して切り上げます。

3
activealexaoki

以下は、値を合計する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への依存関係を削除できることに注意してください。

1
David Beckman

以下は、正または負の数を指定された小数点以下の桁数に丸めます。

sub round ()
{
    my ($x, $pow10) = @_;
    my $a = 10 ** $pow10;

    return (int($x / $a + (($x < 0) ? -0.5 : 0.5)) * $a);
}
1
seacoder

浮動小数点数全体(つまり、12347.9999または54321.0001)から整数値を取得することにのみ関心がある場合、このアプローチ(上記から借用および変更)でトリックが行われます。

my $rounded = floor($float + 0.1); 
0
HoldOffHunger

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 );
0
Akvel