浮動小数点数の解像度が原点からさらに低下するのはなぜですか?


19

OpenGLシーンには、原点から途方もなく遠くに位置するオブジェクトがあります。これらのオブジェクトを表示し、それらの周りでカメラをパン/回転/ズームすると、それらは「ジッター」します。つまり、オブジェクトを構成する頂点は、点の仮想3Dグリッドの周りにスナップしているように見えます。これは、浮動小数点精度(OpenGL、および他のほとんどすべてが使用する)を使用して格納できる情報量が多いため、よくある問題であると読みました。なぜこれが起こるのかわかりません。

解決策を探しているときに、非常に単純な「浮動原点」の修正に出会いましたが、うまくいくようです。オブジェクトが同じ相対位置にあるようにすべてを変換するだけですが、カメラの視線はすべて原点に近くなります。ここで説明を見つけました:http : //floatingorigin.com/、しかし、私はそれに従うことができませんでした。

だから...なぜ私のシーンを原点から非常に遠く(たとえば1000万単位)に配置すると、私が観察した不規則な行動になるのかを説明できますか?また、なぜ原点に近づけると問題が解決するのでしょうか?


4
彼らがそうしなかったならば、彼らは固定小数点数であるだろうから。トートロジーの質問、これ。
–MSalters

1
本当ですが、「浮動小数点」が本当に何を意味するかを理解している場合のみです。
キロタン

回答:


26

これは、コンピューターでの浮動小数点の表現方法によるものです。

整数は非常に簡単に保存されます。各単位は、数えられる数字で予想されるように、「前の」単位とまったく異なる「1つの」単位です。

浮動小数点数では、これは正確には当てはまりません。代わりに、いくつかのビットは指数を示し、残りは仮数、または指数部(暗黙的に2 ^ exp)で乗算された小数部として知られているものを示し、最終結果を提供します。

ビットの視覚的な説明はこちらご覧ください。

この指数がビットの実際の部分であるため、正確に数値が大きくなるとWANEの精度が始まります。

これを実際に見るために、核心に入らずに擬似浮動小数点表現を行ってみましょう。2のような小さな指数を取り、テストするために小数部分を行います。

2 * 2 ^ 2 = 8

3 * 2 ^ 2 = 12

4 * 2 ^ 2 = 16

...等。

これらの数値は、指数2で大きく離れることはありません。しかし、指数38を試してみましょう。

2 * 2 ^ 38 = 549755813888

3 * 2 ^ 38 = 824633720832

4 * 2 ^ 38 = 1099511627776

おっ、今大きな違い!

この例は、特に次の可算数(ビット数に応じて次の小数部分になります)には行きませんが、数値が大きくなると精度の低下を示します。floatの「次の可算」ユニットは、指数が小さいと非常に小さく、指数が大きいと非常に大きくなりますが、整数では常に1です。

float originメソッドが機能する理由は、これらの潜在的に大きな指数の浮動小数点数をすべて小指数にスケーリングするため、「次の可算数」(精度)が非常に小さくて幸せになるためです。


あなたが与えた例は本当に実例でした、ありがとう:)
プリス

3
正しい軌道に乗っていますが、浮動小数点が実際に機能する方法により近い例を使用してほしいと思います。仮数を指数に上げません。仮数* 2 ^指数です。
ネイサンリード

3
あなたは正しい、私はそれを知っていました。何を考えていたのか分かりません。私の答えを編集しました。

1
@ScottWニース編集!+1
ネイサンリード


8

この分野の古典を育てなければなりません。すべてのコンピューター科学者が浮動小数点数について知っておくべきこと

しかし、その要点は、単精度(倍精度)浮動小数点数が32ビット(64ビット)2進数で、1ビットが符号、8ビット(11ビット)の基数2の指数を表すことに関係しています。 、および23ビット(52ビット)の仮数(括弧はdoubleの値です)。

つまり、単精度で表現できる最小の正数は0.0000000000000000000001 x 2 -127 = 2 -22 x 2 -127 = 2 -149〜1.40 x 10 -45です。

次の正の数は、その二重である:X 2 0.0000000000000000000010 -127 = 2 -148〜2.80×10 -45、その後次の番号は前の二つの0.0000000000000000000011×2の合計である-127 = 3×2 -149〜4.2 - 45

0.1111111111111111111111 X 2:これは、まで、同じ定数差によって増加継続-127 = 2 -126 - 2 149〜1.17549435×10 -38 - 0.00000014×10 -38 = 1.17549421×10 -38

これで、通常の数字(仮数の最初の桁が1)に到達しました:1.0000000000000000000000 x 2 -126 = 2 -126 = 1.17549435 x 10 -38そして次の数字は1.0000000000000000000001 x 2 -126 = 2 -126です(1 + 2 -22)= 1.17549435 x 1.00000023。


2

浮動小数点数が原点から離れると精度が低下する理由は、浮動小数点数が大きな数を表すことができるためです。これを実行する方法は、「浮動小数点」という用語に適しています。可能な値(ビット長によって決定される)を分割して、各指数にほぼ同じ数が存在するようにします。32ビットの浮動小数点の場合、23ビットのビットが仮数または仮数を定義します。そのため、各指数範囲で2 ^ 23の異なる値の値を取ることができます。これらの指数範囲の1つは1-2 [2 ^ 0〜2 ^ 1]であるため、範囲1〜2を2 ^ 23の異なる値に分割すると、多くの精度が得られます。

しかし、範囲[2 ^ 10〜2 ^ 11]を2 ^ 23の異なる値に分割すると、各値の間のスペースがはるかに大きくなります。そうでなければ、23ビットでは十分ではありません。すべてが妥協です。実数を表現するには、無限のビット数が必要です。アプリケーションが、より大きな値に対してより低い精度で逃げることができる方法で機能し、実際に大きな値を表すがある場合、浮動小数点表現を使用します。


7年後のさらなるレビューでここにメモするだけです...私の例の私の数字は特に適切に選択されていません。しかし、全体的なポイントは有効です。
スティーブンルー

1

浮動小数点の精度がどのように機能するかの特定の例を提供するのは少し難しい場合があります。他の答えを補うために、ここに一つあります。3桁の仮数と1桁の指数を持つ10進浮動小数点数があるとします。

仮数×10 指数

指数が0の場合、0〜999の範囲のすべての整数を正確に表すことができます。1の場合、基本的にその範囲のすべての要素に10を掛けるので、範囲は0〜9900になります。しかし今では、精度が3桁しかないため、10の倍数しか正確に表現できません。指数が最大9の場合、表現可能な整数の各ペアの差は10億です。文字通り、精度を範囲と交換しています。

2進浮動小数点数でも同じように機能します。指数が1増加すると、範囲はになりますが、その範囲内の表現可能な値の数は半分になります。これは小数にも当てはまりますが、これはもちろん問題の原因です。


0

一般に、解像度に指数値(2 **指数部)が乗算されるため、解像度は悪化します。

joshのコメントを認めて:上記は簡潔なステートメントに答えを入れることだけでした。もちろん、http://floatingorigin.com/で指摘しようとしたように、これは全体的なソリューションに向けて始まったばかりであり、プログラムはさまざまな場所からのジッターを持つ可能性があります:精密パイプラインまたはコードの他の部分。


これにより、他の回答にまだ存在しないものは追加されません。

真実:答えを1行で説明できることに気づき、簡潔な答えが役立つと誰かが思うかもしれないと思った。
クリスソーン14年

-1

OpenGL深度バッファは線形ではありません。あなたが行くほど、解像度は悪くなります。これを読むことをお勧めします。そこから取ったもの(12.070):

要約すると、パースペクティブディバイドは、その性質により、ビューボリュームの前面近くで、背面近くよりもZ精度が高くなります。

そしてもう一つ(12.040):

デプスバッファの精度を大幅に制限する方法で、zNearおよびzFarのクリッピングプレーンを構成した可能性があります。通常、これは、zNearクリッピングプレーンの値が0.0に近すぎるために発生します。zNearクリッピングプレーンが次第に0.0に近づくように設定されると、深度バッファーの有効な精度が劇的に低下します。zFarクリッピングプレーンを目からさらに離すと、深度バッファーの精度に常にマイナスの影響がありますが、zNearクリッピングプレーンを動かすほど劇的ではありません。

そのため、近くのクリッピングプレーンをできるだけ遠くに移動し、遠いプレーンをできるだけ近くに移動する必要があります。


-1:質問は浮動小数点の精度に関するものであり、非線形深度バッファ表現の精度の問題ではありません。
ネイサンリード

私が見ているのは、深度バッファリングの問題が原因である可能性があります。OpenGLの上部にあるlibを使用してシーンを表示し、カメラ、ビュー、および近くと遠くのクリッピングプレーンを設定して、ジオメトリのサイズと位置を考慮します(ビューアーから)ツールはシーンのコンテンツに最適なビューを自動的に設定するようです)。しかし、これはそうではないかもしれないと思います-元の位置をそのままにして、クリッピングプレーンで遊んでみて、何が起こるか見てみましょう。
プリス

2Nathan Reed:著者は、彼がOpenGLシーンを持っていると書いたので、私もそれがこの問題かもしれないと思った。
-zacharmarz

この問題は類似または関連しているように見えるかもしれませんが、深度バッファの値は浮動小数点数と互換性のある方法で保存されていないことは間違いありません。これは固定小数点形式です。このため、答えが誤解を招く可能性があります。
スティーブンルー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.