問題タブ [single-precision]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 4つの複合バイトから32ビットフロートを構築する
4つの複合バイトから32ビットのfloatを構築しようとしています。次の方法よりも優れた(またはよりポータブルな)方法はありますか?
floating-point - 倍精度浮動小数点数はどのように単精度浮動小数点形式に変換されますか?
数値を倍精度浮動小数点形式から単精度浮動小数点形式に変換すると、精度が失われます。この変換を達成するために使用されるアルゴリズムは何ですか?
数値は、それぞれの制限に単純に削減されるよりも大きい3.4028234e+38
か小さいか? -3.4028234e+38
変換プロセスはこれよりも少し複雑だと思いますが、ドキュメントが見つかりませんでした。
c# - 64ビットマシンでx86コンパイル済みコードを実行すると、単精度演算が壊れます
でMSDNSystem.Single
を読むとき:
Single
バイナリ浮動小数点演算のIEC60559:1989(IEEE 754)標準に準拠しています。
およびC#言語仕様:
およびタイプは、32ビット単精度および64ビット倍精度IEEE754形式を使用して表されます[...
float
]double
以降:
積は、IEEE754算術の規則に従って計算されます。
float
タイプとその乗算がIEEE754に準拠しているという印象を簡単に得ることができます。
乗算が明確に定義されているのはIEEE754の一部です。つまり、2つのインスタンスがある場合、それらの「正しい」製品はfloat
1つだけ存在するということです。float
製品がそれを計算するシステムの「状態」または「セットアップ」に依存することは許されません。
ここで、次の簡単なプログラムについて考えてみます。
Appartは、環境とコンパイル構成に関する情報を記述して、2つfloat
のs(つまりa
とb
)とそれらの製品を考慮します。最後の4つの書き込み行は興味深いものです。Debug x86(左)、Release x86(中央)、およびx64(右)でコンパイルした後、64ビットマシンでこれを実行した場合の出力は次のとおりです。
float
単純な操作の結果は、ビルド構成に依存すると結論付けます。
後の最初の行は、2つのs"case .58"
が等しいかどうかの簡単なチェックです。float
ビルドモードから独立していると期待していますが、そうではありません。float
次の2行は、aをにキャストするために何も変更しないため、同一であると予想されますfloat
。しかし、そうではありません。また、製品をそれ自体"True↩ True"
と比較しているので、彼らが読むことを期待しています。a*b
出力の最後の行はビルド構成から独立していると予想されますが、そうではありません。
正しい製品が何であるかを理解するために、手動で計算します。0.58
(a
)のバイナリ表現は次のとおりです。
ここで、括弧内のブロックは、永久に繰り返される期間です。この数値の単精度表現は、次のように丸める必要があります。
ここで、最も近い表現可能な値に切り捨てられます(この場合は切り捨てられます)Single
。さて、「百」(b
)の数は次のとおりです。
バイナリで。数値の完全な積を計算すると、次のよう(*)
になり(**)
ます。
単精度に切り上げ(この場合は切り上げ)すると、
次のビットが1
ではなく、0
(最も近いものに丸められる)ため、切り上げました。58f
したがって、結果はIEEEに準拠していると結論付けます。IEEEによれば、これは事前に与えられたものではありませんでした。たとえば、は、0.59f * 100f
より小さく、より大きくなります。59f
0.60f * 100f
60f
したがって、x64バージョンのコードが正しく機能しているように見えます(上の図の右端の出力ウィンドウ)。
注:この質問の読者のいずれかが古い32ビットCPUを使用している場合、上記のプログラムの出力がアーキテクチャーでどのようになっているのかを聞くのは興味深いことです。
そして今、質問のために:
- 上記はバグですか?
- これがバグではない場合、C#仕様では、ランタイムが
float
余分な精度で乗算を実行し、その精度を再び取り除くために「忘れる」ことを選択できると言っていますか? float
式を型にキャストすると、どのようにfloat
何かを変えることができますか?- たとえば、一時的なローカル変数にを引き出すことによって式を2つの式に分割するなど、一見無害に見える操作が、
(a*b)
数学的に(IEEEによる)同等である必要があるときに動作を変更するのは問題ではありませんか?float
プログラマーは、ランタイムが「人工的な」追加(64ビット)精度で保持することを選択したかどうかを事前に知ることができますか? - リリースモードでのコンパイルによる「最適化」で演算を変更できるのはなぜですか?
(これは、4.0バージョンの.NET Frameworkで行われました。)
c - Cはどのタイプを期待するかをどのように知るのですか?
すべての値が1バイト以上であり、どのバイトにもメタデータを含めることができない場合、システムはどのようにして1バイトが表す数値の種類を追跡しますか?ウィキペディアで2の補数とシングルポイントを調べると、これらの数値を基数2で表す方法がわかりますが、コンパイラまたはプロセッサ(ここで実際に扱っているのは不明)がこのバイトをどのように決定するのか疑問に思っています。符号付き整数である。
これは、暗号化された手紙を受け取り、私の暗号の棚を見て、どれをつかむべきか疑問に思うことに似ています。何らかの指標が必要です。
この問題を解決するために私が何をすべきかを考えると、2つの解決策が思い浮かびます。追加のバイトを要求してそれを使用して説明を格納するか、メモリのセクションを数値表現専用に割り当てます。符号付き数値のセクション、フロートのセクションなど。
私は主にUnixシステムでCを扱っていますが、これはもっと一般的な質問かもしれません。
floating-point - c_k の精度 = a + ( N + k ) * b
a、b は 32 ビット浮動小数点値、N は 32 ビット整数、k は 0、1、2、... M の値を取ることができます。c_k = a + ( N + k ) * b を計算する必要があります。演算は 32 ビット演算 (倍精度ではない) である必要があります。問題は正確さです。次のうちどれがより正確ですか?:
I) c_k = a + ( N + k ) * b
II) 最初に計算します: c_0 = a + N * b
次に、加算によって c_1、c_2 などを繰り返し計算します:
c_1 = c_0 + b;
c_2 = c_1 + b;
types - IEEE754単精度浮動小数点数の精度が7桁しかないのはなぜですか?
単精度浮動小数点数の精度が 7 桁 (または倍精度の 15 ~ 16 桁) になるのはなぜですか?
float(Sign(32) Exponent(30-23), Fraction (22-0)) に割り当てられた 32 ビットに基づいて、どのように到達するのか説明してもらえますか?
floating-point - MIPS - 一連の整数を単精度浮動小数点数に変換する方法
この問題にアプローチする方法を理解するのに本当に苦労しています。整数と小数の両方のバイナリ表現を取得し、それらを仮数に結合し、符号ビットを先頭に割り当てたいと思いますが、MIPS で実際に実装する方法がわかりません。
少なくとも始めるのを手伝ってくれる人はいますか?
MIPS ハードウェアに浮動小数点レジスタと浮動小数点 ALU がないと仮定します。浮動小数点加算を実行する場合は、整数レジスタ ($0 ~ $31) と整数 ALU を使用する MIPS 整数命令を使用して、ジョブを実行する必要があります。この割り当ての問題では、整数命令と整数レジスタのみを使用して MIPS コードを記述し、2 つの浮動小数点数を加算するプロシージャを実装し、プロシージャを呼び出すメイン関数を記述します。
MIPS プロシージャ toFloat を記述して、浮動小数点数を IEEE 単精度形式に変換します。このプロシージャは、次のように浮動小数点数を表す $a0、$a1、$a2 の 3 つの整数を入力として取ります。浮動小数点数が負です。レジスタ $a1 に格納されている数値は浮動小数点数の整数部分であり、レジスタ $a2 に格納されている数値は浮動小数点数の小数部分です。たとえば、浮動小数点数 -5.25 を表示するには、3 つの入力レジスタに $a0 = 1、$a1 = 5、および $a2 = 25 の数値が含まれている必要があります。小数部分には、div rs rt を使用できます。 25 を 100 で割る命令. 分数は HI レジスタに格納され、mfhi 命令を使用して分数を取得できます。このプロシージャは、3 つの入力数値で表される浮動小数点数に対応する IEEE 単精度パターンを含む v0 を返します。この手順を実行したら、それを使用して入力数値 2.5 および 7.5 を IEEE 単精度形式に変換できます。
MIPS プロシージャprintFloatを記述して、IEEE 単精度形式の数値を出力します。プロシージャの入力は、IEEE 単精度形式の数値である $a0 にあります。このプロシージャは、$a0 に格納されているビット パターンを単純に出力します。ループを使用して各ビットを出力できます。この手順を実行したら、それを使用して入力数値2.5および7.5を浮動小数点形式で出力できます。
プロシージャを呼び出すメイン関数を実装する MIPS プログラムを作成します。このプログラムでは、
toFloat(0, 2, 5) は 2.5 の浮動小数点形式を生成します。
toFloat(0, 7, 5) は 7.5 の浮動小数点形式を生成します。
2.5を印刷するprintFloat
7.5を印刷するprintFloat
これが私がこれまでに持っているコードです:
floating-point - 大きな 10 進数を浮動小数点表現に変換する
10 進数を IEEE 754 単精度浮動小数点表現に変換する方法は知っていると思いますが、確認したいと思います。
IEEE 754 単精度浮動小数点表現で 3.398860921 x 10^18 を表現したい。フロート担当者を知っています。壊れています。
31 桁目: 符号 (+ の場合は 0、- の場合は 1) 30 ~ 23 桁目: 指数を表す 22 ~ 0 桁目: 仮数 (仮数) を表す
正の数なので、符号は明らかに 0 です。指数については、これを思いつき(バイアスの127に18を追加することにより)、指数を次のように表しました:1001 0001
3.398860921 の部分となる仮数部については、小数点の右側にあるすべてのものを継続的に 2 で乗算し、それが 1 より大きい場合は 1 をマークし、それ以外の場合は 0 をマークしました。仮数部を埋めるのに十分なビットを思いつくまで、小数点以下 2 を 2 ずつ増やしました。
だから今私は持っています: 0 | 1001 0001 | 0110 0110 0001 1011 1011 111
これを HEX に変換すると 0x48B30DDF が得られますが、これは 3.398860921 x 10^18 で始めた数値とは異なります。
そんなはずなのか、どこかで間違えたのか。どんな助けでも大歓迎です。
java - なぜ 8099.99975f != 8100f なのですか?
編集:浮動小数点演算が正確ではないことは知っています。そして、算数は私の問題でさえありません。追加により、私が期待した結果が得られます。8099.99975f
しません。
だから私はこの小さなプログラムを持っています:
IEEE 754単精度浮動小数点数として書かれたときに8099.99975
が丸められるかどうかを確認するために書きました。8100
驚いたことに、Java8099.9995
は float リテラル ( 8099.99975f
) として記述された場合に変換します。計算と IEEE 規格を再度確認しましたが、間違いは見つかりませんでした。8100
は as と同じくらい離れて8099.99975
いますが、 is8099.9995
の最後のビットは正しい表現にする必要があります。8100
0
そこで、Java 言語仕様をチェックして、何か見落としがないかどうかを確認しました。簡単に検索したところ、次の2つのことがわかりました。
-
Java プログラミング言語では、すべての浮動小数点演算子が浮動小数点の結果を結果の精度に丸めるかのように、浮動小数点演算が動作する必要があります。不正確な結果は、無限に正確な結果に最も近い表現可能な値に丸めなければなりません。最も近い 2 つの表現可能な値が等しく近い場合は、最下位ビットが 0 の値が選択されます。
-
Java プログラミング言語は、浮動小数点値を整数に変換するときに、ゼロ方向への丸めを使用します [...]。
ここで、float リテラルについて何も言われていないことに気付きました。したがって、float リテラルは、float にキャストすると、float から int へのキャストと同様にゼロに丸められるだけの double である可能性があると考えました。8099.99975f
これにより、がゼロに丸められた理由が説明されます。
上記の小さなプログラムを書いて私の理論を確認したところ、2 つの float リテラルを追加すると8100
、正しい float が計算されることがわかりました。(ここで、8099.9995
and0.00025
は単一の float として正確に表すことができるため、別の結果につながる可能性のある丸めはありません) float リテラルと計算された float の動作が異なることはあまり意味がなかったので、これは私を混乱させました。言語仕様をもう少し調べて、これを見つけました:
浮動小数点リテラルは、ASCII 文字の F または f [...] の接尾辞が付いている場合、float 型です。float [...] 型の要素は、IEEE 754 32 ビット単精度 [...] バイナリ浮動小数点形式を使用して表現できる値です。
これは最終的に、リテラルを IEEE 標準に従って丸める必要があることを示しています。この場合は8100
です。では、なぜ8099.9995
ですか?
c++ - 10 進数から IEEE 単精度浮動小数点
ビットごとの演算子のみを使用して、整数値を IEEE 単精度浮動小数点形式に変換する方法を学ぶことに興味があります。ただし、指数を計算するときに必要な論理シフトの数を知るために何ができるかについて、私は混乱しています。
15 などの int を指定すると、次のようになります。
バイナリ: 1111
-> 1.111 x 2^3 => 最初のビットの後に小数点を置くと、「e」の値が 3 になることがわかります。
E = Exp - バイアス したがって、Exp = 130 = 10000010
仮数は次のようになります: 111000000000000000000000
ただし、最初のビットの後に 10 進数を配置すると 3 ビットあることがわかったので、「e」の値が 3 になることはわかっていました。一般的なケースとして、これをコーディングするより一般的な方法はありますか?
繰り返しますが、これは int から float への変換です。整数が負でもゼロでもなく、仮数部に許可されている最大スペースよりも大きくないことを前提としています。
また、23ビットを超える値に丸めが必要な理由を誰かが説明できますか? 前もって感謝します!