2013-07-21 10 views
7

ghciで5.2 - 2.3を実行すると2.9ではなく2.9000000000000004になります。 また、このような醜い(そして人間の誤った)結果は、DoubleまたはFloatを使って作業するときに他の場所にも現れます。醜い二倍 - なぜ2.9000000000000004の代わりに2.9?

どうしてですか?

私の本当の質問: ghciにはそうしないように指示し、他のプログラミング言語(および電卓)と同じように、Doublesでの演算結果を表示するにはどうすればよいですか?まさに15歳ごとに書いていますか?

ghciを素晴らしい電卓として使用し、そのような操作を実行するリストで作業するとき、これはちょっと面倒です。

map ((-)2.3) [4.0, 3.8, 5.2, 6.4, 1.3, 8.3, 13.7, 9.0, 7.5, 2.4] 
[-1.7000000000000002,-1.5,-2.9000000000000004,-4.1000000000000005,0.9999999999999998,-6.000000000000001,-11.399999999999999,-6.7,-5.2,-0.10000000000000009] 

紙に先立って、その後

感謝を数字を使用する場合は、単に助けにはならない:)

+3

これはサイドコメントと同じように、おそらくこれまでの歴史のなかで最もよく聞かれる質問です。 –

答えて

8

ghciには、他のプログラミング言語(および電卓)と同じように、また15歳ごとに書き込むように、演算結果をDoublesで表示するにはどうすればよいですか?

これらの結果は、GHCiの(および標準の電卓*が)あなたは結果(see TNI's answer)の内部表現を変更することはできません算出し、実際の結果なので。小数点以下桁数を固定して表示する場合は、プレゼンテーション(Cのprintf("%f.2",...)と比較)の問題があります。

この解決策は、https://stackoverflow.com/a/2327801/1139697にあります。これは次のように適用できます。

import Numeric 
fixedN :: (RealFloat b) => Int -> b -> String 
fixedN a b = showFFloat (Just a) b "" 

map (fixedN 2 . (-)2.3) [4.0, 3.8, 5.2, 6.4, 1.3, 8.3, 13.7, 9.0, 7.5, 2.4] 
-- result: ["-1.70","-1.50","-2.90","-4.10","1.00","-6.00",...] 

計算を続行したい場合は、これは実現できません。 正確に算術を使用する場合は、とにかくRationalsを使用する方がよいでしょう。あなたの入力が合理的でなければならないことを忘れないでください。

※はい、標準的な電卓でも同じことがありますが、固定表示では表示されない唯一の理由は、固定小数点数以上は表示できません。

+1

実際、より単純なポケット計算機の多くは[BCD](http://en.wikipedia.org/wiki/Binary-coded_decimal)を使用しています。この問題は、平方根よりも高度な処理を効率的に行うにはまったく適していません。あなたは人間の計数方法でバグを回避すると言うことができます... – leftaroundabout

18

は、なぜこれが起こるのでしょうか?

特定の浮動小数点数は、丸めを行わずに有限数のビットで表現できないためです。 Floating-point numbersは数字の桁数が限られているため、real numbersのすべてを正確に表すことはできません。フォーマットよりも多くの桁がある場合、残りの数字は省略されます。

おそらくWhat Every Computer Scientist Should Know About Floating-Point Arithmeticthis answerと読みます。

+2

実際には、ここで見ているようにすべての有理数を表すことさえできません –

3

浮動小数点数の性質上、実際の(合理的な)数字を正確に表すことはできません。 Haskellの文字列へのデフォルト変換は、数値が読み込まれたときに、同じ表現を得ることを保証します。数字を印刷する別の方法が必要な場合は、数字を別々に表示する独自のタイプを作成できます。 (未テスト)のような

何か:これはDoubleタイプのコピーを作成しますが、ほんの数小数を出力異なるShowインスタンスと

newtype MyDouble = MyDouble {getMyDouble :: Double} 
      deriving (Eq, Ord, Num, Real, RealFrac, Fractional, Floating) 
instance Show MyDouble where show = printf "%g" . getMyDouble 
default (MyDouble) 

default宣言は、あいまいさがある場合にコンパイラにこの型を選択させます。ああ、この仕事をするには、いくつかの言語拡張が必要です。

numbersパッケージからCRealタイプを試すこともできます。

3

は、どのように私はそれを行うと、ちょうど他のプログラミング言語(電卓) が

は、あなたが実際にしてみてくださいましたでしょう「他を兼ねての操作 の結果を表示しないようにGHCiのを教えてくださいプログラミング言語 "?それともあなたはいじめをしていますか?

FWIWは、ここにJVMを使用する言語のインタプリタの出力です:あなたはすべてのJVM言語と同じ結果を得るかのよう

frege> 5.2 - 2.3 
2.9000000000000004 

は、私には見えます。また、JVMはC++で書かれているので、結果は同じである可能性があります。ほとんどの言語のランタイムはC/C++で書かれているので、それらの言語でも同じ結果が得られる可能性があります。彼らが「ユーザーフレンドリー」で、あなたが求めなかった丸めを実行しない限り。

関連する問題