Skip to content

Instantly share code, notes, and snippets.

@m-ou-se
Created September 12, 2015 14:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m-ou-se/c00c4ef81ce93002cb2c to your computer and use it in GitHub Desktop.
Save m-ou-se/c00c4ef81ce93002cb2c to your computer and use it in GitHub Desktop.
constexpr functions to encode and decode IEEE754 binary64 doubles.
#include <iostream>
#include <vector>
#include <cstdint>
constexpr double decode_double(std::uint64_t encoded) {
bool s = encoded >> 63;
std::int16_t e = encoded >> 52 & 0x7FF;
std::int64_t m = encoded & (1ULL << 52) - 1;
if (e == 2047) return m ? s ? 0/0.0 : -(0/0.0) : s ? -1/0.0 : 1/0.0;
double x = m | (e ? 1ULL << 52 : 0);
e -= 1024 + 51 - (e == 0);
while (e > 0) { x *= 2; --e; }
while (e < 0) { x /= 2; ++e; }
return s ? -x : x;
}
constexpr std::uint64_t encode_double(double x) {
bool s = !(x == 0 ? 1/x >= 0 : x >= 0);
if (s) x = -x;
int e = 1024 + 51;
while (!(x <= (1ULL << 53)) && e < 2047) { x /= 2; ++e; }
while (x < (1ULL << 52) && e > 1) { x *= 2; --e; }
std::uint64_t m = e < 2047 ? x : std::uint64_t(!(x == x)) << 51;
if (e == 1 && !(m >> 52 & 1)) e = 0;
m = m & (1ULL << 52) - 1;
return std::uint64_t(s) << 63 | std::uint64_t(e) << 52 | m;
}
int main() {
std::vector<double> testcases{
1, -123e-100, 1234e100, 0.7e-308, -1.3e-308, 1.1e308,
1/0.0, -1/0.0, 0/0.0
};
for (double d : testcases) {
std::cout << std::hex << reinterpret_cast<std::uint64_t const &>(d) << ' ' << d << std::endl;
auto e = encode_double(d);
std::cout << std::hex << e << ' ' << decode_double(e) << std::endl;
std::cout << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment