初めて a 0.1 + 0.2 === 0.3 バグは、生産で私を噛んだ、私はほとんどの開発者がすることをした: 私は検索、見つけた" フローティングポイントは奇妙です," そして、移動しました 私は実際にビットを見て、理由を理解する何年も前にあった 私がやったら、数値バグの全体のカテゴリは、神秘的であることを停止しました このガイドは、IEEE 754 コンバータが示すもの、を使用して、 IEEE 754 コンバーター Toolz.dev では、なぜ記号、指数、仮数を見つめることが、コンピューターが小数をどのように保存するかについての真の直観を構築する最も早い方法です。
tl;dr: コンピュータは、IEEE 754 標準に従って、浮動小数点数を符号、2 のべき乗、および分数仮数として保存します。 IEEE 754 コンバータは、3.14159 のような 10 進数をそれらの正確なビットにエンコードし、ビットを 1 つの値にデコードします。 IEEE 754 コンバーター 符号、指数、仮数を分解して、単一精度と二重精度の両方を完全にブラウザで実行します。
IEEE 754 とは?
IEEE 754 は、1985 年に初めて発行され、として改訂された規格です IEEE 754-2019、コンピュータが浮動小数点数を二進数で表す方法を定義するものである。 ほぼすべてのCPU、GPU、プログラミング言語がそれに従うため、a double c、java、python、javascriptでも同じように動作します。 "floating point, " と言われると、ほとんどの場合、IEEE 754 バイナリ浮動小数点を意味します。
中心となる考え方は数値を3 つの部分に格納するというものです正または負と書かれた符号ビットがあります値を2 のべき乗でスケールする指数がありますそして正確な数字を保持する仮数部または仮数部とも呼ばれます普通の数字は符号に1.mantissaに2 を掛けた指数ですこれは科学的表記法で基数2 で固定されたビット数に詰め込まれています。
毎日会う2 つの形式は binary32 と呼ばれる単一精度と binary64 と呼ばれる二重精度です。 single は 1 つの符号ビット、8 つの指数ビット、23 の仮数ビット、合計 32 ビットを使用します。 double は 1 つの符号ビット、11 の指数ビット、52 の仮数ビット、合計 64 ビットを使用します。 double はほとんどの言語のデフォルトの浮動小数点型です。 single は GPU とメモリに敏感なコードで一般的です。
IEEE 754 コンバータは実際に何をしますか?
IEEE 754 コンバータは、数値を取得し、その正確なビット パターンを表示します。これら 3 つのフィールドに分割され、16 進数形式とビットから読み返される値とともに表示されます。これは、エンコードするために 10 進数を入力するか、2 進数または 16 進数のビット パターンを貼り付けて、それが表す数値にデコードします。
On Toolz.dev ワークフローが短い. single または double precision を選ぶ.入力が小数か16 進ビットパターンか2 進ビットパターンかを選ぶ.値を入力する.ツールは符号ビット,指数フィールド,仮数,全ビット,16 進数,偏った指数と偏らない指数の両方,そして正確に格納された値を示す.すべてのフィールドにはコピーボタンがある.
あなたの言語が印刷する番号を信頼するのではなく、これらすべてを見る理由は、印刷された番号が省略によって嘘をついているからです コンソールが表示されたとき 0.1、丸みを帯びたフレンドリーなレンダリングを示しています。 bits は実際に何が保存されているかを教えてくれます。これら 2 つの違いは、浮動小数点バグが存在する場所です。
なぜ0.1 プラス0.2 は0.3 に等しくないのですか?
これが標準的な例であり、コンバーターはそれを具体化します。値 0.1 は 2 進浮動小数点で正確に表現できません。同じ理由で、1/3 は 10 進数で正確に記述できません。 10 進数では、1/3 は 0.3333...永遠に。 2 進数では、0.1 は決して終了しない繰り返し分数であるため、52 の仮数ビットに収まるように丸める必要があります。
0.1 のダブルをデコードし、ビットが実際に保持する値は 0.100000000000000005551115123125782702181583404541015625 です。 0.2 のダブルも同様に髪が大きすぎます。 2 つの丸みを帯びた値を追加すると、結果は 0.3 より少し大きくなりますが、0.3 のダブルは少し小さくなります。したがって、2 つは等しくありません。何も壊れていません。各ステップは、IEEE 754 が要求することを正確に実行しており、コンバーターを使用すると、信仰に基づいて実行するのではなく、それが起こるのを見ることができます。
これを見た後、修正は自然に続きます。正確な等価性を得るためにフロートを比較しないでください。小さな許容範囲内で比較したり、お金のために整数セントを使用したり、正確な 10 進数の算術が必要な場合は 10 進数のライブラリを使用したりします。このバグは加算には含まれていませんでした。 10 進数の分数を正確に保存するバイナリ形式を期待するためでした。
符号、指数、仮数とは何ですか?
各フィールドには特定のジョブがあり、コンバーターは 3 つすべてにラベルを付けます。
符号ビットは最も単純です。0 は正を意味し、1 は負を意味します。符号が別個のビットであるため、IEEE 754 には正のゼロと負のゼロの両方があり、比較では等しく動作しますが、異なるビットを持ちます。
指数体は2 のべき乗を格納しますが、バイアスが加算されているため、別の符号なしで負の指数を表すことができます。バイアスは単精度で127、二重で1023 です。したがって、単精度で格納された指数体127 は、実際の指数がゼロであることを意味します。 Toolz.devコンバータは両方の数値を示します:ビットに住むバイアスされた値と、それが実際に適用される2 のバイアスのない力。その区別は多くの人をつまずかせます。そのため、ツールは頭の中で減算するのではなく、それを綴ります。
仮数は仮数の小数部分を保持します。正規化された 2 進仮数は常に 1 で始まるため、正規化された 2 進仮数は常に 1 で始まるため、形式には省略することで自由ビットの精度が得られます。そのため、仮数フィールドが 23 ビットと 52 ビットであるにもかかわらず、単一精度では約 7 桁の 10 進数が与えられ、二重精度では約 15 ~ 16 桁が与えられます。
2 つのフォーマットがフィールドごとにどのように並ぶかは次のとおりです:
| 財産 | シングル (binary32) | ダブル (binary64) |
|---|---|---|
| 合計ビット数 | 32 | 64 |
| サインビット | 1です | 1です |
| 指数ビット | 8です | 11 |
| 仮数ビット | 23 に記載しております | 52 に記載しております |
| 指数バイアス | 127 に準拠して作成されています | 1023 に準拠しております |
| 約10進数 | 7です | 15から16まで |
| 通称 | 浮遊物 | ダブル |
ビットを小数に戻すにはどうすればよいですか?
デコードはエンコードと同じくらい便利で、メモリ ダンプ、バイナリ ファイル形式、または生のフロートを保存するネットワーク プロトコルから値を読み取る方法です。入力タイプを Hex または Binary に設定し、精度が期待する正確なビット パターンを貼り付けます。1 つは 16 桁または 32 ビット、2 つは 16 桁または 64 ビットです。
例えば、単精度ヘックス 40490FDB 円周率に最も近いフロートである 3.1415927 にデコードします。コンバーターはオプションも受け入れます 0x 接頭辞を付けてスペースやアンダースコアを無視するため、グループ化されたバイトを見つけたときに貼り付けることができます。間違った桁数を与えると、静かに切り捨てるのではなく、その精度に必要な数値が正確に示されます。これは、より多くのツールがわざわざ書きたいと思っています。
この復号方向は自然に一般とペアになります ナンバーベースコンバータ 浮動小数点解釈なしで、10 進数、16 進数、2 進数、8 進数の間で値を移動する必要がある場合 バイナリ トランスレータ 数字ではなくテキストで作業しているとき。私は 3 つすべてに頻繁に手を伸ばし、ブックマークの同じ隅に住んでいます。
無限、NaN、ゼロはどのように表されますか?
特別な値は、IEEE 754 が賢くなる場所であり、コンバーターは各ケースを識別するため、パターンを記憶する必要はありません。
指数体はスイッチの役割を果たします すべての指数ビットが1 のとき 特別な範囲にいるのです 全零仮数は無限大を意味し ゼロ以外の仮数は数値ではなく NaNを意味します 正と負の無限大は符号ビットによってのみ異なります NaNはゼロをゼロで割ったような演算や 負の平方根から得るもので それ自体は等しくないという有名な性質を持っています。
すべての指数ビットが 0 の場合、あなたは他の特別な範囲にいます。つまり、すべてゼロの仮数はゼロであり、符号ビットに応じて正または負であり、ゼロ以外の仮数は非正規数です。非正規数は、ゼロと最小の正規数の間のギャップを埋め、非常に小さな大きさを表す能力を取引します。 1 からバイアスを引いた有効指数を使用し、コンバーターがバイアスのない指数を示すときに考慮する暗黙の先頭 1 をドロップします。
指数体がすべてゼロでもすべて 1 でもない他のすべては通常の数値です。ビット パターンを一目見て、これら 5 つのケースのうちどれを見ているかを瞬時に知ることができることは、計算によって期待していなかった値が生成されるときの真のデバッグ スーパーパワーです。
実際にこれが必要なのはいつですか?
一度調べることを知ったら、あなたが推測するよりも頻繁に必要です。数値結果が丸めエラーによってずれているときにそれに手を伸ばし、その値が正確に表現可能かどうかを確認したい バイナリシリアライザ、ファイル形式、またはフロートを格納するワイヤプロトコルを書き込むかデバッグするときに使用するため、意図したものとバイトが一致することを検証できます。 GPUシェーダーが使用できるかどうかを判断するなど、単一精度と二重精度を比較する場合に不可欠です float あまり正確さを損なうことなく。フィールドを見ると抽象的な標準が具体的になるため、これはコンピュータ アーキテクチャに関して私が知っている最も明確な教材の一つです。
私のようにスタックをまたいでビルドすると 浮動小数点が意外な場所に現れます Laravel APIでの価格計算 Reactでのキャンバスアニメーション 座標をめちゃくちゃにするCSVエクスポート ストレージフォーマットを理解することは、それらすべてで報われる小さな投資です このようなツールがどのように幅広いキットに適合するかについて書きました Web 開発者ツールキット、そして 数ベースコンバータガイド あんど バイナリ翻訳者ガイド 近隣の低レベルの変換をより詳しくカバーします。
浮動小数点精度の限界は?
ビットが見えるようになると 形式の限界は抽象的ではなくなります ダブルには52 個の保存された仮数ビットに 暗黙の先頭1 を加えたものがあり 大体15 から16 桁の 10 進数になります それを追い越すと 精度は静かに蒸発します ダブルが表現できる最大の整数は その間の値で まだ正確です 2の53 乗です 9007199254740992 これに1 つ加えると 結果は丸め戻されます なぜなら 次の表現可能な値は1 つではなく2 つ離れているからです これがすべての数値にdoubleを使う言語が さらけ出す理由です その中のJavaScriptは Number.MAX_SAFE_INTEGER まさにその値で一定であり、JSON 番号として送信される大規模なデータベース ID がサイレントに破損する可能性がある理由。
1 つの表現可能な値と次の値の間のギャップは、最後の場所の単位、またはULPと呼ばれ、大きさが成長するにつれて大きくなります。 1.0 付近の間隔は小さい; 10 億近くは数百; 最大倍近く、10の308 分の1 の約1.8 倍、隣り合う間のギャップは天文学的に大きく、変換器がこれを可視化します: 2 つの近くの大きな数をエンコードすると、それらの間に表現がないだけなので、同じビットを共有していることがよくわかります。 ULPを理解することは、フォーマットが提供できる以上の解像度を期待するのを妨げるものです。
関連するトラップが破滅的なキャンセルです 2 つのほぼ等しい浮動小数点数を減算すると 先頭の桁がキャンセルされ そもそも最も精度の低い部分だった 低次のビットが残ります 結果は丸め誤差に支配される可能性があります 各入力が正確に見えたにもかかわらず これが数値的に注意深いコード順序変更操作で 近い量の減算を回避する理由であり 素朴なループでフロートの長いリストを合計すると 誤差が蓄積する理由です カハン総和のような優れたアルゴリズムでは 回避できます。
実用的なポイントは一貫しています。 float としてお金を保存しないでください; 0.10 のような値は正確に表現できず、エラーは何千ものトランザクションにわたって複合するため、整数セントまたは 10 進数型を使用します。 floats を正確に比較しないでください; 問題に応じたサイズの許容範囲内で比較してください。そして、非常に大きな整数が往復でも生き残らなければならない場合は、それを文字列として保持するか、ダブルを信頼して保持するのではなく任意の精度の整数型を使用します。これらの各ルールは、フォーマットがなぜそのように動作するかをコンバーターが示した後、覚えやすくなります。
よくある質問
小数をIEEE 754 に変換するにはどうすればよいですか?
単一精度または二重精度を選択し、入力タイプを10 進数に保ち、数値を入力して変換します ツールは値をIEEE 754 ビットパターンにエンコードし、符号ビット、指数フィールド、仮数、完全バイナリ、および16 進数のすべてをブラウザで実行します。
単精度と倍精度の違いは何ですか?
Single precision (binary32) は、1 符号、8 指数、23 仮数の32 ビットを使用し、10 進数約7 桁の精度が得られます。 double precision (binary64) は、1 符号、11 指数、52 仮数の64 ビットを使用し、約15 から16 桁になります。 doubleは、ほとんどの言語のデフォルトのfloat型です。 singleは、GPUやメモリ制約コードで一般的です。
なぜ0.1 は正確な値に変換されないのですか?
1/3 に有限小数点がないのと同様に、0.1 には 2 進浮動小数点での有限表現がありません。最も近い表現可能な倍数は 0.10000000000000000005551115125782702181583404541015625 です。コンバーターはビットから読み戻された保存値を示すため、0.1 + 0.2 が 0.3 に等しくないなどの丸め驚きを引き起こす小さな違いがわかります。
符号、指数、仮数とは何ですか?
符号ビットは正の場合は 0、負の場合は 1 です。指数フィールドにはバイアスが追加された 2 のべき乗が格納されます (シングルの場合は 127、ダブルの場合は 1023)。そのため、ツールはビット内のバイアスされた値と、適用されるバイアスされていないべき乗の両方を示します。仮数は仮数の小数部分を保持し、通常の数値では暗黙的に先頭に 1 が付きます。
IEEE 754 ビットを小数に戻すことができますか?
はい。入力タイプを Hex または Binary に設定し、正確なビット パターンを貼り付けます。単一精度では 8 16 桁または 32 ビット、二重精度では 16 16 桁または 64 ビットです。ツールはそれをデコードし、それが表す小数点をフィールド全体の内訳とともに示します。
無限、NaN、ゼロはどのように表されますか?
すべての指数ビットが 1 の場合、すべてゼロの仮数は無限大を意味し、ゼロ以外の仮数は NaN を意味します。すべての指数ビットが 0 の場合、すべてゼロの仮数はゼロ (符号ビットに応じて正または負) で、ゼロ以外の仮数は非正規数になります。コンバーターはこれらのケースにそれぞれラベルを付けます。
このツールを機密番号に使用しても安全ですか?
はい。変換は完全にブラウザの JavaScript で実行されます。ネットワーク リクエストには入力が送信されず、何も保存されず、ページが読み込まれるとツールはオフラインで動作するため、入力した値はデバイスに残ります。
コンバータはどのような16 進フォーマットを期待していますか?
平野の16 進数桁、オプションの0xプレフィックスとグループ化のためのスペースまたはアンダースコアがあり、無視されます。 single precisionは8 hex digit、double precisionは16 を期待します。 たとえば、40490FDBはsingle-precision pi (3.1415927) です。
無料を使って自分でビットを探索してください IEEE 754 コンバーター。単一精度と二重精度のフロートをエンコードおよびデコードするため、何もアップロードされずに完全にブラウザーに表示されます。



