2015-12-21 7 views
8

私はPerlで書かれたアカウンティングスクリプトに取り組んでいます。私は十進数計算を行うための「適切な」方法が何であるか疑問に思っています。Perlで小数点演算を実行するにはどうすればよいですか?

"0.1" + "0.1" + "0.1" == "0.3" 
"258.9" * "2000" == "517800" 
... 

はPythonでは、私は値のためDecimalタイプを使用したいが、私はPerlで何をしますか:例えば、私はこのような比較が正常に動作することを保証したいですか?

+3

Math :: BigRatとMath :: Decimalはこのトリックを行います。 – ikegami

+1

小数点および整数から引用符を削除します。 –

+4

@Missaka Wijekoon、引用符は無害です。あなたはその点を欠いている。 'perl -E'say 0.1 + 0.1 + 0.1 == 0.3を試してみてください。 "equal": "not equal" '' – ikegami

答えて

8

(注:Math::Currencyがありますが、現在壊れています)。

Math::BigFloatを使用して任意の精度のオブジェクトとして数値を表します。

use Math::BigFloat; 

print Math::BigFloat->new(0.1) + 
     Math::BigFloat->new(0.1) + 
     Math::BigFloat->new(0.1) == Math::BigFloat->new(0.3); 

あなたはbignum ...

use bignum; 

print 0.1 + 0.1 + 0.1 == 0.3; 

と、自動的にこれを行うことができますが!魔法はの番号にしか作用しません。一緒に文字列を追加しようとすると、それは動作しません、魔法は遅すぎます。明示的に数字にする必要があります。文字列を数値化するには、$a += 0のように文字列に0を加えることができます。または、式を0 +で始めることによってbignumsとして強制することができます。これにより、行がカスケードされます。

use bignum; 

$a = "0.1"; 
$b = "0.1"; 
$c = "0.1"; 
$d = "0.3"; 

# False 
print $a + $b + $c == $d; 

# True 
print 0 + $a + $b + $c == $d; 

2つの注意点。

まず、このすべてが大きなパフォーマンスコストになります。任意の精度の計算を行うだけでなく、すべてのメソッドとオーバーロードマジックのために。これが許容可能かどうかを判断するためにベンチマークしてください。幸いにもbignumは、プログラム全体ではなく、そのスコープ内の数字だけをアップグレードします。 bignumのスコープ外の数字を使用することも安全です。それらの数字もアップグレードされます。

次に、Decimalは有効数字を保持します。 Math :: BigFloatはできません。

+0

'Math :: BigFloat'は私にとってはうまくいくようですが、浮動小数点演算であることは明らかです。私は小数演算を行うためのコアモジュールがないことに驚いています。 –

+2

@engene y、Math :: BigRatは無損失算術演算を行い、5.8.0以来コアになっています。 – ikegami

+1

@eugeneyこれは整数で行われています。 「0.01」は指数が「2」で「1」になる。すべての任意の精度ライブラリは、非常に非常に簡単にメモリを使い切ることができる他の精度には限界があります。たとえば、「1/3」です。 PythonのDecimalは30か所で停止します。 Math :: BigFloatは40になります。[Math :: BigFloatではこの問題について説明しています](https://metacpan.org/pod/Math::BigFloat#Accuracy-vs.-Precision)。精度を上げるには、[Math :: BigRat](https://metacpan.org/pod/Math::BigRat)を使用します。分数を分数として格納します。 'ビッグラットを使う。 print 1/3'は '1/3'を返します。 – Schwern

-4

私が知っている最良の方法は、絶対差が公差未満であることでテストすることです。例えば:

perl -e '$ x = 0.1 + 0.1 + 0.1; $ y = 0.3; $ q = abs($ x - $ y)< 0.0001? "等号": "等しくない"; $ qを印刷します。 "\ n"; '

+3

アカウンティングシナリオでの浮動小数点数の使用は非常に悪い考えです。これは、これらの丸め誤差の累積ではありません。 – tjd

+0

[POSIX.pm](https://metacpan.org/pod/POSIX)から実際のイプシロンを得ることができます。 'POSIX qw(DBL_EPSILON);を使う' – Schwern

関連する問題