sprintf() による四捨五入は避けるべきでは
http://d.hatena.ne.jp/perlcodesample/20080922/1222147231
「サンプルコードによるPerl入門」は、よく参考にしていますが、sprintf() による四捨五入には疑問に思うことがありました。「四捨五入を行うには、sprintf関数を使用します」と紹介しておきながら、次のようなことも書かれています。
数値リテラルで表現した0.725は、内部的には0.725ではない為、 sprintf( "%.2f", $num2)は 0.73 にはなりません。
次のようなscriptで実験を行ってみても、確かに sprintf( "%.2f", $num2)は 0.73 にはなりません。
#!perl use strict; use warnings; for my $val (qw/0.723 0.725 0.727/){ print "Round $val ->",sprintf( "%.2f", $val),"\n"; }
$ ./test.pl Round 0.723 ->0.72 Round 0.725 ->0.72 Round 0.727 ->0.73
しかし、本来、sprintf()はFORMAT指定による整形済み文字列を返すものなので、四捨五入は避けるべきではないでしょうか?
わざわざ int()で四捨五入methodは書きたくない
また、次のurlでは sprintf()やint()によって「$num を四捨五入して小数点以下 $decimals桁にする」を紹介していますが、四捨五入の為にここまで書きたくはありません。
http://www.din.or.jp/~ohzaki/perl.htm#NumberRound
sub round { my ($num, $decimals) = @_; my ($format, $magic); $format = '%.' . $decimals . 'f'; $magic = ($num > 0) ? 0.5 : -0.5; sprintf($format, int(($num * (10 ** $decimals)) + $magic) / (10 ** $decimals)); }
更にint()による四捨五入を紹介しているサイトをよく見かけますが、int()には脆弱性もあるようです。
my $int_val = int($float_val + 0.5);
私の場合、Math::Round::nearest を使っています
私の場合、数値演算にはMath系モジュールをよく使用しますが、その中でも四捨五入には Math::Round::nearest を使っています。
http://search.cpan.org/perldoc?Math::Round
#!perl use strict; use warnings; use Math::Round qw/nearest/; for my $val (qw/0.723 0.725 0.727/){ print "Round $val ->",nearest(0.01,$val),"\n"; }
$ ./foo.pl Round 0.723 ->0.72 Round 0.725 ->0.73 Round 0.727 ->0.73
Math::Roundは標準モジュールではありませんが、私の場合、四捨五入を必要とする機会が多くないので、これで十分です。