浮動小数点演算には精度の問題があることを認識しています。私は通常、数値の固定10進表現に切り替えるか、単にエラーを無視することでそれらを克服します。
しかし、この不正確さの原因はわかりません。浮動小数点数に非常に多くの丸めの問題があるのはなぜですか?
コメント
回答
これは、一部の分数を丸めずに表現するには、非常に大量の(または無限の)場所が必要になるためです。これは、2進数やその他の表記と同様に、10進表記にも当てはまります。計算に使用する小数点以下の桁数を制限する場合(および小数表記での計算を避ける場合)、単純な式でも1/3 +1/3として丸める必要があります。結果として2/3を書き込む代わりに、0.33333 + 0.33333 = 0.66666を書き込む必要がありますが、これは2/3と同じではありません。
コンピュータの場合、桁数は技術的な性質によって制限されます。そのメモリとCPUレジスタの。内部で使用されるバイナリ表記は、さらにいくつかの問題を追加します。コンピュータは通常、数値を分数表記で表現できませんが、一部のプログラミング言語ではこの機能が追加されているため、これらの問題をある程度回避できます。
すべてのコンピューター科学者が浮動小数点演算について知っておくべきこと
コメント
- スポットを当てます。しかし、いくつかの数字は10進数で終了しない’ tはバイナリで終了します。特に0.1はバイナリの繰り返し数であるため、浮動小数点のバイナリ番号が0.1を正確に表すことはできません。
- 浮動小数点ポイントは’小数点以下の桁数が多い場合にのみ役立ちます。32ビットの整数は最大で約40億までしかカウントできませんが、32ビットの浮動小数点数はほぼ無限に大きくなる可能性があります。
- 特に、有限小数として表現できる分数は、分母’の主因数分解に2と5しか含まれていないものです(たとえば、3/10と7/25を表現できます)。 、 だがしかし 11/18)。 2進数に移行すると、5の因数が失われるため、2進分数(1 / 4、3 / 128など)のみを正確に表現できます。
回答
主に、丸め誤差は、すべての実数の無限大という事実に起因します。 / em>は、コンピュータの有限メモリで表すことはできません。ましてや、単一の浮動小数点変数などのメモリの小さなスライスで表すことはできないため、格納される数値の数は
値の数は限られているため、 ではありません 近似値であり、近似値と別の数値の間の演算は近似値になります。丸め誤差はほぼ避けられません。
重要重要なのは、問題を引き起こす可能性が高い時期を認識し、リスクを軽減するための措置を講じることです。
David Goldberg の重要な すべてのコンピューター科学者t浮動小数点演算について知っておく必要があります (Sun / Oracleによって数値の付録として再公開されました thorsten 、 iv id = “191fb1149e”によって言及された計算ガイド) >
ACCU ジャーナル 過負荷 は、 iv id = “725e5c176e]について、リチャードハリスによる優れた一連の記事を掲載しました。 “> 浮動小数点ブルース 。
シリーズは
- で始まりました。 あなたは考える必要があります! in オーバーロード#99 ( pdf 、p5-10):
Numerical co mputingには多くの落とし穴があります。リチャード・ハリスは銀の弾丸を探し始めます。
数値エラーのドラゴンは眠りから覚醒することはあまりありませんが、不注意に近づくと、不注意なプログラマーの計算に壊滅的なダメージを与えることがあります。
IEEE 754浮動小数点演算の森で彼に偶然出会った一部のプログラマーが、その公正な土地を旅行しないように仲間にアドバイスするほどです。
この一連の記事では、調査します。数値計算の世界。浮動小数点演算を、より安全な代替として提案されているいくつかの手法と対比しています。ドラゴンの領域は実際に広範囲に及んでおり、一般に、彼を恐れる場合は注意深く踏まなければならないことを学びます。壊滅的な注目。
リチャードは、実数、合理的、非合理的、代数的、超越的な数値の分類を説明することから始めます。次に、キャンセルエラーと実行順序の問題に進む前に、IEEE754表現について説明します。
これより深く読まなければ、浮動小数点数に関連する問題の優れた根拠が得られます。 。
ただし、詳細を知りたい場合は、続けます
- 固定小数点が浮動小数点ブルーを修復しない理由 in オーバーロード#100 ( pdf 、p15-22)
- 根拠がない理由オーバーロード#101 ( in div id = “725e5c176e”> pdf 、p9-13)
- コンピューター代数が浮動小数点ブルーを修復しない理由 in 過負荷# 102 ( pdf 、p9- 14)。
- 間隔アルゴリズムが浮動小数点ブルーを修復しない理由 in オーバーロード103 ( pdf 、p19-24)
次に、彼はあなたが Calculus Blues
最後になりましたが、重要なことですが、
- 自動微分で微積分ブルースが硬化しない理由 in オーバーロード108 ( pdf 、p4-11)。
一連の記事全体は調べる価値は十分にあり、合計66ページで、ゴールドバーグ紙の77ページよりもまだ小さいです。
これはシリーズは同じ分野の多くをカバーしていますが、ゴールドバーグの紙よりもアクセスしやすいことがわかりました。また、リチャーズの以前の記事を読んだ後、論文のより複雑な部分を理解しやすくなり、それらの初期の記事の後、リチャードはゴールドバーグの論文では触れられていない多くの興味深い領域に分岐しました。
コメントで言及されているしたがって、spake ak として:
の作成者としてこれらの記事は、ブログ www.thusspakeak.com で thusspakeak.com/ak/2013/06 。
コメント
- これらの記事の作成者として、’ブログwww.thusspakeak.comで、 thusspakeak.com/ak/2013/06 。
- @ thusspakea.kに感謝します。’メモを追加しました私の答えに、そしてトーこれらのインタラクティブな要素は非常にうまく機能します。
回答
そうですね、 thorsten には、決定的なリンクがあります。追加します:
どのような形式の表現でも、いくつかの数値に対して丸め誤差が発生します。 1/3をIEEE浮動小数点または10進数で表現してみてください。どちらも正確にそれを行うことはできません。これはあなたの質問に答えるだけではありませんが、私はこの経験則をうまく使用しました:
- ユーザーが入力した値を10進数で保存します(ほぼ確実に10進数で入力したため、ユーザーはほとんどいません) 2進数または16進数を使用します)。そうすれば、常に正確なユーザー入力表現が得られます。
- ユーザー入力分数を保存する必要がある場合は、分子と分母(これも10進数)を保存します。
- 同じ数量の複数の測定単位(Celsius / Fahrenheitなど)を備えたシステムで、ユーザーは両方を入力し、入力した値と入力した単位を保存できます。変換して単一の表現として保存しようとしないでください。精度/精度を損なうことなくそれを行うことができない限り、すべての計算で保存された値およびの単位を使用してください。
- マシンで生成された値をIEEE浮動小数点に保存します(これは生成された数値である可能性があります) A / Dコンバーターを備えたアナログセンサーなどの電子測定デバイス、または四捨五入されていない計算結果による)。これは、シリアル接続を介してセンサーを読み取り、すでに与えている場合は適用されないことに注意してください。値を小数形式(例:18.2 C)で入力します。
- ユーザーが表示できる合計などを小数で保存します(銀行口座など)。残高)。適切に丸めますが、その値を今後のすべての計算の最終的な値として使用します。
コメント
- 追加します。 ARPRECやdecNumberなどの任意精度の数学パッケージ。
- ‘ 10進数(2進数ではなく)は、分子などの整数値に大きなメリットがあります。分数の分母。どちらも正確な整数値を格納でき、バイナリの方が効率的です。 ‘入出力の変換にはある程度のコストがかかりますが、’は物理的なコストに圧倒される可能性がありますI / Oを実行します。
回答
これまで言及されていないように思われるのは、不安定なアルゴリズムの概念です。 と悪条件の問題。前者については、初心者の数値計算者にとってより頻繁な落とし穴のように思われるため、最初に説明します。
(逆数の)黄金比の累乗の計算を検討してくださいφ=0.61803…
;これを実行する1つの可能な方法は、φ^0=1
およびivid = “で始まる再帰式φ^n=φ^(n-2)-φ^(n-1)
を使用することです。 748c911069 “>
。お気に入りのコンピューティング環境でこの再帰を実行し、その結果を正確に評価された検出力と比較すると、重要な数値がゆっくりと低下することがわかります。たとえば、
Mathematica で何が起こるかを次に示します。
ph = N[1/GoldenRatio]; Nest[Append[#1, #1[[-2]] - #1[[-1]]] & , {1, ph}, 50] - ph^Range[0, 51] {0., 0., 1.1102230246251565*^-16, -5.551115123125783*^-17, 2.220446049250313*^-16, -2.3592239273284576*^-16, 4.85722573273506*^-16, -7.147060721024445*^-16, 1.2073675392798577*^-15, -1.916869440954372*^-15, 3.1259717037102064*^-15, -5.0411064211886014*^-15, 8.16837916750579*^-15, -1.3209051907825398*^-14, 2.1377864756200182*^-14, -3.458669982359108*^-14, 5.596472721011714*^-14, -9.055131861349097*^-14, 1.465160458236081*^-13, -2.370673237795176*^-13, 3.835834102607072*^-13, -6.206507137114341*^-13, 1.004234127360273*^-12, -1.6248848342954435*^-12, 2.6291189633497825*^-12, -4.254003796798193*^-12, 6.883122762265558*^-12, -1.1137126558640235*^-11, 1.8020249321541067*^-11, -2.9157375879969544*^-11, 4.717762520172237*^-11, -7.633500108148015*^-11, 1.23512626283229*^-10, -1.9984762736468268*^-10, 3.233602536479646*^-10, -5.232078810126407*^-10, 8.465681346606119*^-10, -1.3697760156732426*^-9, 2.216344150333856*^-9, -3.5861201660070964*^-9, 5.802464316340953*^-9, -9.388584482348049*^-9, 1.5191048798689004*^-8, -2.457963328103705*^-8, 3.9770682079726053*^-8, -6.43503153607631*^-8, 1.0412099744048916*^-7, -1.6847131280125227*^-7, 2.725923102417414*^-7, -4.4106362304299367*^-7, 7.136559332847351*^-7, -1.1547195563277288*^-6}
φ^41
の符号が間違っており、それ以前でも、φ^39
の計算値と実際の値は共通の数字を共有していません(3.484899258054952
* ^- 9 for the computed version against the true value
7.071019424062048 *^-9
)したがって、アルゴリズムは不安定であり、この再帰式を不正確な演算で使用しないでください。これは次の理由によるものです。再帰式の固有の性質:この再帰には「減衰」と「成長」の解があり、代替の「成長」解があるときに順方向解によって「減衰」解を計算しようとすると、数値的な悲しみを懇願します。したがって、彼/彼女の数値アルゴリズムが安定していることを確認する必要があります。
次に、悪条件の問題の概念について説明します。安定した方法がある場合でも数値的に何か、それはあなたが持っている問題である可能性が非常に高いですveはあなたのアルゴリズムでは解決できません。これは問題自体のせいであり、解決方法ではありません。数値の標準的な例は、いわゆる「ヒルベルト行列」を含む線形方程式の解です。
行列は、悪条件行列の標準的な例です。大きなヒルベルト行列を使用してシステムを解こうとすると、不正確な解が返される可能性があります。
ここで Mathematica デモンストレーション:正確な計算の結果を比較する
Table[LinearSolve[HilbertMatrix[n], HilbertMatrix[n].ConstantArray[1, n]], {n, 2, 12}] {{1, 1}, {1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}
不正確な計算
Table[LinearSolve[N[HilbertMatrix[n]], N[HilbertMatrix[n].ConstantArray[1, n]]], {n, 2, 12}] {{1., 1.}, {1., 1., 1.}, {1., 1., 1., 1.}, {1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 1., 1., 1., 1., 1., 1.}, {1., 1., 1., 0.99997, 1.00014, 0.999618, 1.00062, 0.9994, 1.00031, 0.999931}, {1., 1., 0.999995, 1.00006, 0.999658, 1.00122, 0.997327, 1.00367, 0.996932, 1.00143, 0.999717}, {1., 1., 0.999986, 1.00022, 0.998241, 1.00831, 0.975462, 1.0466, 0.94311, 1.04312, 0.981529, 1.00342}}
( Mathematica で試してみた場合は、「悪条件が表示されることを警告するエラーメッセージがいくつか表示されます。)
どちらの場合も、単に精度は治療法ではありません。それは数字の避けられない侵食を遅らせるだけです。
これはあなたが直面するかもしれないものです。解決策は難しいかもしれません。最初に、あなたは画板に戻るか、ジャーナル/本/何でも調べて、他の誰かがあなたよりも良い解決策を思いついたかどうかを見つけます。第二に、あなたはあきらめるか、問題をより扱いやすいものに再定式化します。
Dianne O “Learyからの引用を残しておきます:
人生は私たちにいくつかの悪条件の問題を投げかけるかもしれませんが、不安定なアルゴリズムを受け入れる正当な理由はありません。
回答
ベース10の10進数はベース2で表現できないため
つまり、1/10は表現できないため分母で2の累乗の分数に変換されます(これは基本的に浮動小数点数です)
コメント
- 正確には当てはまりません:0.5 0.25は2進数で表すことができます。”すべての10進数の10進数”ではないことを意味すると思います。
- より正確に。すべての小数を浮動小数点表記を使用して正確に表すことができるわけではありません(つまり、基数2と基数10の両方にこの正確な問題があります)。
9*3.3333333
を10進数で実行し、9*3 1/3
- これが浮動小数点の最も一般的なソースです。錯乱。
.1 + .1 != .2
浮動小数点バイナリエンコーディングが使用されているため、10進数ではありません。 - @SeanMcMillan:および
1.0/3.0*3.0 != 1.0
、浮動小数点であるため-3進数ではなく、ポイント2進数エンコードが使用されます。
回答
数学には、無限に多くの有理数があります。 。 32ビット変数は2 32 の異なる値のみを持つことができ、64ビット変数は2 64 の値のみを持つことができます。したがって、正確な表現がない有理数は無限にあります。
1/3、つまり1/100を完全に表現できるスキームを考え出すことができます。多くの実用的な目的では、これはあまり有用ではないことがわかります。1つの大きな例外があります。財務では、小数がポップアップすることがよくあります。これは主に、財務は本質的に人間の活動であり、物理的な活動ではないためです。
したがって、通常は2進浮動小数点を使用し、2進で表現できない値は丸めます。ただし、財務では、10進浮動小数点を選択し、値を最も近い10進値に丸めることがあります。 。
コメント
- さらに悪いことに、無限(数え切れないほど無限)のメモリ量では、すべての論理的根拠を表すことができますが、そうではありません。実数を表すには十分です。さらに悪いことに、ほとんどすべての実数は計算可能な数値ではありません。有限量のメモリで実行できる最善の方法は、実数の有限範囲サブセットを近似することです。
- @Kevin:’計算可能な数値について話しています。これは、実数の小さなサブセット(小数がゼロのサブセット)です。
- +1最も基本的な説明:’有限のビット数で無限の数を表現しようとしています。
- @DavidHammen:計算可能な数値は小さなサブセットです(実数のゼロ)ですが、プログラムで’使用するすべての数値は、定義上、計算可能です。
- @Giorgio:If適切な表現を選択すると、2の平方根は、たとえば文字列
"√2"
として表現できます。 (私の古いHP-48計算機はそれを正確に行うことができ、その値を2乗すると、正確に2.0
になりました。)任意の表現可能な実数の可算無限大のみがあります。 有限表現-しかし、計算によって、原則として表現できない数を生成することはできません。実際には、2進浮動小数点は、表現可能な数値のセットを大幅に制限し、シンボリック表現に比べて非常に高速でストレージが小さいという利点があります。
回答
私が考える浮動小数点数の唯一の本当に明白な「丸めの問題」は、平均フィルターの移動に関するものです:
$$ \ begin {align} y [n] & = \ frac {1} {N} \ sum \ limits_ {i = 0} ^ {N-1} x [ni] \ & = y [n-1] + \ frac {1} {N}(x [n] –x [nN])\ \ end {align} $$
ノイズの蓄積がある場合は、現在のサンプルに追加する$ x [n] $が、将来$ N $サンプルを差し引く$ x [nN] $と正確に同じであることを確認する必要があります。そうでない場合、異なるのは、遅延線に引っかかって出てこない小さな糞です。これは、この移動平均フィルターが実際には、$ z = 1 $でわずかに安定した極と、内部でそれをキャンセルするゼロを持つIIRで構築されているためです。しかし、それは積分器であり、統合されて完全に削除されないがらくたは、積分器の合計に永遠に存在します。これは、固定小数点が浮動小数点数と同じ問題を抱えていない場所です。
コメント
- ねえ、’ t $ LaTeX $数学マークアップはprog.SEフォーラムで機能しませんか??? that ‘ ‘ t。
- これはmeta.SO とリンクされた質問
decimal
タイプのしくみ。一方、固定小数点は異なります。範囲が限られている限り、固定小数点は良い答えです。ただし、範囲が制限されているため、固定小数点は多くの数学アプリケーションには不適切であり、固定小数点数の実装は、結果としてハードウェアで十分に最適化されていないことがよくあります。