Skip to content

Instantly share code, notes, and snippets.

@wakita
Last active August 29, 2015 14:24
Show Gist options
  • Save wakita/efc3ce97439c154384b4 to your computer and use it in GitHub Desktop.
Save wakita/efc3ce97439c154384b4 to your computer and use it in GitHub Desktop.
単精度浮動小数点数の表現形式に関するハック
#undef NDEBUG
#include <iostream>
#include <cassert>
using std::cout;
using std::endl;
// 1:8:23
typedef unsigned int uint;
// 23: 7:16
const uint EXP_MASK ((1 << 8) - 1);
const uint FRC_MASK ((1 << 23) - 1);
const uint B23 (1 << 23);
void p(float v) {
uint x = *reinterpret_cast<uint *>(&v);
uint s = x >> 31;
uint e = (x >> 23) & EXP_MASK;
uint f = x & FRC_MASK;
cout <<
v << "\t-> " << (s ? '1' : '0') << ", " <<
std::hex << e << ", " <<
std::hex << f << std::dec << endl;
}
float fn1(int n) {
if (n == 0) return 0.f;
const uint s = 0;
uint e = 0x7f;
uint f = n, g = 0;
while (f > 1) {
g = ((f & 1) << (23 - 1)) | (g >> 1);
f >>= 1; e++;
}
uint x = (s << 31) | (e << 23) | g;
return *(reinterpret_cast<float *>(&x));
}
float fn2(int n) {
if (n == 0) return 0.f;
const uint s = 0;
uint e = 0x7f + 23;
uint f = n;
while (!(f & B23)) {
f <<= 1; e--;
}
uint x = (s << 31) | (e << 23) | (f & FRC_MASK);
return *(reinterpret_cast<float *>(&x));
}
float f01_1(int n) {
if (n == 0) return 0.f;
const uint s = 0;
uint e = 0x7f;
uint f = n;
while (!(f & B23)) {
f <<= 1; e--;
}
uint x = (s << 31) | (e << 23) | (f & FRC_MASK);
return *(reinterpret_cast<float *>(&x));
}
int main() {
# define F 24
for (int n = 0; n < (1 << F); n++) {
float f = (float)n / (1 << F);
assert (n == (uint)(f * (1 << F)));
}
cout << "floatの精度が" << F << "あることを確認しました。" << endl << endl;
// fn1: n -> (float)n の確認
for (int n = 0; n < (1 << 23); n++) {
if (n <= 8 || (1 << 23) - 8 < n) {
p((float)n);
p(fn1(n));
cout << endl;
}
assert(fn1(n) == (float)n);
}
cout << "fの実装の正しさを確認しました。" << endl << endl;
// fn1: n -> (float)n の確認
cout << endl;
for (int n = 0; n < (1 << 23); n++) {
if (n <= 8 || (1 << 23) - 8 < n) {
p((float)n);
p(fn2(n));
cout << endl;
}
assert(fn2(n) == (float)n);
}
cout << "fn2の実装の正しさを確認しました。" << endl << endl;
for (int n = 0; n < 23; n++) {
assert(f01_1(1 << n) * (1 << (23 - n)) == 1);
}
cout << "f01_1の実装の正しさを確認しました。" << endl << endl;
for (int n = 0; n < (1 << 23); n++) {
if (n <= 8 || (1 << 23) - 8 < n) {
p((float)n);
p(f01_1(n));
cout << endl;
}
assert(f01_1(n) * (1 << 23) == n);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment