キャスティングとは、あるものから別のものに変換することです。16 ビットまたは 32 ビットに対する 8 ビットの整数である可能性があります。
unsigned int x;
unsigned char y;
y = 7;
x = (unsigned int) y;
x=y; を実行した場合、これはもちろん暗示されます。ここでは、8 ビットと 32 ビットの typedef を想定しています。ビット パターン 0x07 から 0x00000007 になります。
これは実際にはとても楽しいエクササイズです。フォーマットを作成してから、質問について考えてみましょう。
浮動小数点形式は通常、このようなことを行います。純粋に正の数で考えて、この演習のほとんどを行うことができます。底が 10 の数 1234 を取り上げます。小学校での科学的表記法について話します。これは 1.234 の 10 の 3 乗になります。ベース 2 コンピューター形式は、浮動小数点と呼ばれる理由があって同じように機能します。小数は仮想的な意味で移動します。したがって、float の 9 番目の 0b1001 は、最上位のものを見つけて、その後に 1.001 かける 2 の 3 乗です。17 の数字 1.0001 かける 2 の 4 乗です。浮動小数点は符号をカバーする必要があります。整数全体でも分数を強制しているため、「分数」または仮数にはいくつかのビットが必要です。そして指数。一部の形式で想定できる小数点の前の値を保持する必要は必ずしもありません。もちろん、ゼロは特別な問題であり、浮動小数点形式には特別な例外またはパターンが必要です。この形式には、適用される 2 の累乗を表すビット数も必要です。手始めに、正の整数のみが生成され、整数が 8 ビットであるため、0 から 0xFF が整数の全世界であると仮定します。double 形式には小数部のビットが 12 あり、single には 5 があります。手始めに、正の整数のみが生成され、整数が 8 ビットであるため、0 から 0xFF が整数の全世界であると仮定します。double 形式には小数部のビットが 12 あり、single には 5 があります。手始めに、正の整数のみが生成され、整数が 8 ビットであるため、0 から 0xFF が整数の全世界であると仮定します。double 形式には小数部のビットが 12 あり、single には 5 があります。
1.111111100000 の 2 の 7 乗を 12 の小数ビットで簡単に表すことができる最悪のケースの数値 0xFF は何であり、この演習全体をカバーするのに十分な数の指数ビットがフォーマットにあると仮定します。
だから私たちの double は C で私たちの整数のすべてを保持することができます
dx = ダブル (x);
ビットパターン 00001001 で開始した場合はフォーマットを変換することを意味します。これは数字の 9 であり、2 の 3 乗の 1.001000000000 倍になる構成された double では、フォーマットに保存するビットがさらに多くなりますが、この質問には関係ありません。 .
私たちの作ったシングルでは、9 は 1.00100 かける 2 の 3 乗です。
しかし、単精度の数値 0xFF は 1.11111 かける 2 の 7 乗です。これを整数に戻すと、0xFF ではなく 0xFC になり、変換でいくつかのビットが失われます。丸めなしと仮定します。基数 10 では、1/27 は 0.0307307307 です...これを 4 桁で切り捨てると、0.0307 になり、少し低くなります。しかし、丸めで 0.031 を 3 にすると、少し高すぎます。シングルで 0xFF を見ると、1.11111 であり、次の 2 ビットが投げられて 11 であり、半分以上であるため、10.00000 を 2 の 7 乗に切り上げると、1.00000 の 2 の 8 乗に正規化されます。0xFF は基本的に 0x100 に丸められます。0xff を表す 0x100 または 0xFF を表す 0xFC を使用することもできますが、正確ではありません。逆に変換すると、少し高いか、または少し低くなります。
したがって、最初のケース A (float)x vs (float)((double)x) を見てください。1.00100 かける 2 の 3 乗 vs 1.001000000000 かける 2 の 3 乗。 float x と double x をカバーする場合、double を変換する必要があります。 、浮動小数点形式間で整数から浮動小数点として同じクリッピングと丸めが使用されていますか? ハードウェアによって異なりますが、11111111 が 1.111111100000 と同じように変換されることを期待できますが、理想的な世界では変換されない可能性があります。
C は興味深いケースで、次のように言えます。正の数 最悪の場合 3 + 3 = 6 それをスケールアップするビット数 0xFF と 0xFF では、倍精度形式で 12 を超えるビット数は何ですか? 0xFF と 0xFF と 0xFF を足すと、何ビットかかりますか? 12以上ですか?グループ化を再配置すると、それが変わりますか?
D 2 ビット数 3*3 = 9 オペランドごとに 2 ビット入力 アウトは何ビット? 0xFF×0xFF? 次に、0xFF x 0xFF x 0xFF は 12 ビット以上かかりますか? 最初の質問です。2 番目の質問である場合、クリッピングと丸めはどのように機能しますか? グループ化によってクリッピングと丸めが影響を受けます。ここまでは頭脳派です。理解するには簡単なプログラムを書かなければならないかもしれません。
そして、Eは最初に考えたほど厄介ではなく、読み直しました。ビットパターンを正確なビットパターンで分割しています。コンピューターだけでなく、一般的に除算に関する最大の問題は何ですか?どの整数が私たちに問題を与え、他の問題を引き起こしますか? ここで、正の x を正の x で割った値と負の z を負の z で割った値に符号付きの数値を許可するとどうなるでしょうか?
ウィキペディアで倍精度浮動小数点を検索してから、単精度を検索してください。double にはいくつの「小数」ビットがありますか? そして、32 ビットまたは 31 と int の符号を仮定すると、すべての有効数字が適合しますか? 正の数を考えると、31 の 2 の累乗になるので、31 を表すのに多くの指数ビットが必要になるでしょうか? 十分ですか?分数に31ビットまたは30ビットの有効ビットを保持できますか?指数でプラスまたはマイナス 31 の累乗を表すことができますか?
編集
そこでケースを考えて DI はプログラムを書きました。私は小数部の8ビットを使用しました
//5 9 f 020140 030120 0301E0 090151 090152
(5 * 9) * 15 vs 5 * (9 * 15)
5 は 1.01000000 または 0x1.40、9 は 1.00100000 または 0x1.20、0xF は 1.11100000 または 0x1.E0 です。
float での乗算は、あなたが考えるのと同じではありません。5 かける 9 を直接乗算していないため、頭が少し痛くなります。1 になるようにすべてをシフトしました。
0x120 * 0x140 = 0x16800
その正規化のために、8 ビットを切り捨てます。これは、後で説明するように丸めた場所です。この場合、結果は 0x168 であり、正規化は必要ありません。
5*9 = 0x2D = 101101
1.01101000 0x1.68
指数を気にする必要はありませんが、5 の指数は 2、9 の指数は 8 であるため、結果は指数が 5 の 0x168 になるため、0x168 に 0x1E0 = 0x2A300 を掛けると、性質上 8 ビット 0x2A3 が即座に切り捨てられます。乗算の。ここで、2.something ではなく 1.soemthing が必要なので、右にシフトして指数を増やします。指数は 5+3=8 です。もう 1 つ 9 を付けますが、0x2A3 0x1010100011 に注意してください。 0x1.51.51 ビットの半分の代わりに、基数 2 の浮動小数点の性質である 0x1.51 があります。さて、それは答えを切り上げることになっていますか?多分。もしそうなら、答え0x1.52
Take it the other way 5*(9*15)
0x120*0x1E0 = 0x21C00
or 0x21C 1000011100
0x10E
0x140*0x10E = 0x15180
we are going to lose a bit here
is it 0x151 or 0x152?
そして、これらは同等の丸めの質問ですか? 両方のパスの結果が 0x152 になり、それらが等しくなりますか?それとも、ビットを切り落とす 1 つのビューが他のパスとは異なりますか? まったく丸めずにクリップするだけの場合、両方の答えは 0x152 になります。
3 11 1f 010180 040110 0401F0 0A018B 0A018A
(3*17)*31 vs 3*(17*31) no rounding just clipping
(3*17)*31
0x180*0x110 = 0x19800
0x198
0x198*0x1F0 = 0x31680 0x316 0x1100010110
0x18B
3*(17*31)
0x110*0x1F0 = 0x20f00
0x107
0x180*0x107 = 0x18A80
0x18A
0x18B != 0x18A
1 つのパスを 2 ビット切り取り、もう 1 つのパスを 1 つだけ切り取りました。それは公平でしたか?全体として取られた 0x31680
110001011010000000
110001011 010000000 with discarded bits on the right
そのように見ると、01 または 010 または 0100 は半分未満であり、3 または 2 の切り上げよりも切り上げられません。1.33 は、基数 10 で 1.4 に切り上げられません。
しかし 0x20F00
100000111100000000
100000111 100000000
これは中間点 1/10、10/100、100/1000 で、半分です。
それは0x108だったはずですか?
0x180*0x108 = 0x18C00
0x18C
0x18C != 0x18B
したがって、丸めをそのように表示しても、順序が一致しないため、違いが生じます。
丸めが間違っていると思うかもしれませんが、それは公平です。もしそうなら、可能なすべての整数パターンが機能しますか? int が 32 ビットで、double が 52 ビットの仮数部を持つ IEEE754 であると仮定すると、オーバーフローしてビットを切り落とす必要があるため、切り刻みと丸めが発生します。順序は重要ですか?