未定義動作かもしれません
浮動小数点数の内部表現を取得する
整数型はビット演算を駆使して取り出したり std::bitset に突っ込むなどすれば内部表現を簡単に取得できるが, 浮動小数点数はだるい
共用体やポインタ等を利用して, 内部表現が取得しやすい型に無理やり突っ込むというような方法が必要になる
#include <bits/stdc++.h>
using namespace std;
union{ double f; uint64_t d; } bi;
void hoge(double f){
bi.f = f;
cout << bi.f << "\n";
cout << bitset<64>(bi.d) << "\n\n";
}
int main(){
hoge(3.14);
hoge(0);
hoge(-9);
hoge(numeric_limits<double>::max());
hoge(numeric_limits<double>::lowest());
}
3.14
0100000000001001000111101011100001010001111010111000010100011111
0
0000000000000000000000000000000000000000000000000000000000000000
-9
1100000000100010000000000000000000000000000000000000000000000000
1.79769e+308
0111111111101111111111111111111111111111111111111111111111111111
-1.79769e+308
1111111111101111111111111111111111111111111111111111111111111111
おまけ: 大小関係を保ったまま符号なし整数と相互に変換する
自分としてはこちらが本題で, radix heap に小数を突っ込めるようにするためにこういうことを調べた
double と uint64_t は値を表現するために使用しているビット数が同じなので, 上手く大小関係を保つような全単射が作れるはず
とりあえず内部表現そのままを見てみると, 符号の正負と値の大小が逆になってしまっている
ということで最上位ビットを反転させてみる
すると, 元々負数だったもの同士の大小が逆になってしまう (浮動小数点数は abs を持っているので)
ということで, 全ビットを反転させてみる
すると, 大小関係が維持でき, 逆に整数から小数に戻すのも簡単にできる
#include <bits/stdc++.h>
using namespace std;
union{ double f; uint64_t d; } bi;
constexpr int digits = 64;
uint64_t ftod(double f){
bi.f = f;
if(bi.d >> (digits - 1) & 1) bi.d ^= -1ull;
else bi.d ^= 1ull << (digits - 1);
return bi.d;
}
double dtof(uint64_t d){
if(d >> (digits - 1) & 1) d ^= 1ull << (digits - 1);
else d ^= -1ull;
bi.d = d;
return bi.f;
}
void hoge(double f){
bi.f = f;
cout << bi.f << "\n";
cout << bitset<64>(bi.d) << "\n";
uint64_t d = ftod(f);
cout << bitset<64>(d) << "\n";
cout << dtof(d) << "\n\n";
}
int main(){
hoge(3.14);
hoge(0);
hoge(-9);
hoge(numeric_limits<double>::max());
hoge(numeric_limits<double>::lowest());
cout << dtof(0) << "\n";
cout << dtof(-1) << "\n";
}
3.14
0100000000001001000111101011100001010001111010111000010100011111
1100000000001001000111101011100001010001111010111000010100011111
3.14
0
0000000000000000000000000000000000000000000000000000000000000000
1000000000000000000000000000000000000000000000000000000000000000
0
-9
1100000000100010000000000000000000000000000000000000000000000000
0011111111011101111111111111111111111111111111111111111111111111
-9
1.79769e+308
0111111111101111111111111111111111111111111111111111111111111111
1111111111101111111111111111111111111111111111111111111111111111
1.79769e+308
-1.79769e+308
1111111111101111111111111111111111111111111111111111111111111111
0000000000010000000000000000000000000000000000000000000000000000
-1.79769e+308
-nan
nan
おわりに
いい感じに関数作って radix heap に使いたい~
これ使ったら実数で誤差なし二分探索とかできたりするかも? 考えてみます