重複の可能性:
Haskellの範囲とフロート
たとえば、私が入力すると
[0.1, 0.3 ..1]
私はこれを手に入れます:
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
私は期待しました:
[0.1,0.3,0.5,0.7,0.9]
重複の可能性:
Haskellの範囲とフロート
たとえば、私が入力すると
[0.1, 0.3 ..1]
私はこれを手に入れます:
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
私は期待しました:
[0.1,0.3,0.5,0.7,0.9]
試す
map (/10) [1, 3 .. 10]
代わりは。
問題は、浮動小数点数が 2 進分数を使用し、2 進分数が 10 進分数を正確に表すことができないことです。そのため、エラーが発生し、エラーが蓄積されます。
小数が 1/3 を正確に表すことができないのと同じように、2 進数の分数は 1/5 を正確に表すことはできません。
[0.1, 0.3 .. 1]
の省略形です
[0.1,
0.1 + 0.2,
0.1 + 0.2 + 0.2,
0.1 + 0.2 + 0.2 + 0.2,
0.1 + 0.2 + 0.2 + 0.2 + 0.2,
0.1 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2]
もう1つの問題は、次の要素が制限を超えるステップの半分以上になると、制限に等しいか制限を超えた最初の要素の後にリストが停止することです。これが、要素がある理由です。1.0999999999999999
これは、コンピューターで浮動小数点数がどのように表されるかに関する問題です。浮動小数点数を使用した単純な演算は、多くの場合、期待どおりに動作しません。算術演算を繰り返すと、「丸め誤差」が蓄積される可能性があります。つまり、数値を繰り返し加算すると、結果が徐々に悪化する可能性があります(たとえば)。
別の数値表現を使用することで、これらの問題を回避できる場合があります。たとえば、有理数だけを気にする場合は、Rational
型を使用できます。だからあなたはすることができます:
[0.1,0.3..1] :: [Rational]
その結果:
[1 % 10,3 % 10,1 % 2,7 % 10,9 % 10,11 % 10]
これは、丸め誤差のない正解です。Integer
各数値は、2つのsの比率として表されます。特定の状況によっては、浮動小数点数を使用するよりもこれが適切なオプションになる場合があります。
これはまだ上限を超えていますが、浮動小数点数から得られる丸め誤差よりもはるかに簡単に処理できます。
パフォーマンスが重要な浮動小数点数は、おそらくより高速になることに注意してください。
式[e1, e2 .. e3]
は として評価されますenumFromThenTo e1 e2 e3
。これは、浮動小数点数の場合 ( The Haskell 98 Reportから)を意味します。
Float と Double の場合、enumFrom ファミリのセマンティクスは、上記の Int のルールによって与えられます。ただし、要素が
e3+i/2
正のインクリメント i よりも大きくなったとき、またはe3+i/2
負の i よりも小さくなったときにリストが終了します。
これは、浮動小数点数を使用すると、 の最後の要素[e1, e2 .. e3]
が より大きくなることが多くe3
、最大で になる可能性があることを意味しe3+(e2-e1)/2 - ε
ます。