ちょっと前に arton さんのところの「トリッキーなコード」というエントリーを受けて、id:kmt-t さんによる 反応 で引き合いにだされた、逆数を求める C++ のコード。
#include <stdio.h> #define FP_ONE_BITS 0x3F800000 float p, r; p = 1234.121234f; int i = 2 * FP_ONE_BITS - *(int *)&p; r = *(float *)&i; r = r * (2.0f - p * r); printf("inv expected %20.10f approx %20.10f\n", 1/p, r);
=> inv expected 0.0008102932 approx 0.0008049050
これをその場では読み下せなかったのが、なんだか無性にくやしかったのを、最近、Eclipse に CDT を入れ直したときに思い出したので、もうちょっと C++ だのポインタだの浮動小数点数の内部表現だのを勉強してから Squeak の Smalltalk への直訳を再度試みる。で、こんなんでました。
| fpOneBits result value ii | fpOneBits := 16r3F800000. value := 1234.121234 asFloat. ii := 2 * fpOneBits - value asIEEE32BitWord. result := Float fromIEEE32Bit: ii. result := result * (2.0 - (value * result)). ^ 'inverse expected = {1}, avaluerox = {2}' format: {1/value. result}
=> 'inverse expected = 0.000810293164439629, annrox = 0.000804904988199007'
なんでこれで逆数が求まるか、は、まあいいや(ぉぃ)。
1.0 asIEEE32BitWord storeStringBase: 16 " => '16r3F800000' "
というのがミソですかね。あとは、こんなとことか。
World findATranscript: nil. #(0.125 0.25 0.5 1.0 2.0 4.0 8.0) do: [: each | | exp expStr | exp := each asIEEE32BitWord >> (32 - 8 - 1). expStr := exp printStringBase: 2 length: 8 padded: true. Transcript cr; show: each; tab; show: '->'; tab; show: expStr]
0.125 -> 01111100 0.25 -> 01111101 0.5 -> 01111110 1.0 -> 01111111 2.0 -> 10000000 4.0 -> 10000001 8.0 -> 10000010