0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

浮動小数点数の内部表現を取得する

0
Last updated at Posted at 2022-06-17

未定義動作かもしれません

浮動小数点数の内部表現を取得する

整数型はビット演算を駆使して取り出したり 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 に使いたい~
これ使ったら実数で誤差なし二分探索とかできたりするかも? 考えてみます

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?