From 9a98bb40b60a23befdb8806eafee7858b176b653 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Sun, 13 Nov 2016 11:02:57 -0500 Subject: [PATCH] floating point update... --- toolbox/floating_point.cpp | 249 ++++++++++++++++ toolbox/floating_point.h | 499 +++++++++++--------------------- unit_testing/floating_point.cpp | 101 +++++-- 3 files changed, 482 insertions(+), 367 deletions(-) create mode 100644 toolbox/floating_point.cpp diff --git a/toolbox/floating_point.cpp b/toolbox/floating_point.cpp new file mode 100644 index 0000000..c3fcaa3 --- /dev/null +++ b/toolbox/floating_point.cpp @@ -0,0 +1,249 @@ + +#include "floating_point.h" + +#include + +namespace floating_point { + + void info::read_single(const void *vp) { + + uint32_t i; + std::memcpy(&i, vp, 4); + + sign = i >> 31; + one = 1; + exp = (i >> 23) & ((1 << 8) - 1); + sig = i & ((1 << 23) - 1); + + if (exp == 255) { + exp = 0; + if (sig == 0) inf = true; + else { + nan = true; + sig &= ~(UINT64_C(1) << 22); + } + return; + } + + if (exp == 0 && sig != 0) { + // denormalized. + one = 0; + sig <<= 40; //? + exp = -126; + return; + } + + if (exp) exp -= 127; // bias + + // adjust to 64 bit significand. + sig <<= 40; + if (one) sig |= (UINT64_C(1) << 63); + } + + + + + void info::read_double(const void *vp) { + + uint64_t i; + std::memcpy(&i, vp, 8); + + sign = i >> 63; + one = 1; + exp = (i >> 52) & ((1 << 11) - 1); + sig = i & ((UINT64_C(1) << 52) - 1); + + + if (exp == 2047) { + exp = 0; + if (sig == 0) inf = true; + else { + nan = true; + sig &= ~(UINT64_C(1) << 51); + } + return; + } + if (exp == 0 && sig != 0) { + // denormalized. + one = 0; + sig <<= 10; //? + exp = -1022; + return; + } + + if (exp) exp -= 1023; // bias + sig <<= 11; + if (one) sig |= (UINT64_C(1) << 63); + } + + + void info::read_extended(const void *vp) { + + uint64_t i; + uint16_t sexp; + + if (endian::native == endian::little) { + std::memcpy(&i, (const uint8_t *)vp, 8); + std::memcpy(&sexp, (const uint8_t *)vp + 8, 2); + } else { + std::memcpy(&sexp, (const uint8_t *)vp, 2); + std::memcpy(&i, (const uint8_t *)vp + 2, 8); + } + + sign = (sexp >> 15) & 0x01; + exp = sexp & ((1 << 15) - 1); + + one = i >> 63; + sig = i; // includes 1. i & ((UINT64_C(1) << 63) - 1); + + if (exp == 32767) { + exp = 0; + sig &= ((UINT64_C(1) << 63) - 1); + if (sig == 0) inf = true; + else { + nan = true; + sig &= ((UINT64_C(1) << 62) - 1); + } + return; + } + + #if 0 + if (exp == 0 && sig != 0) { + // denormalized. + exp -= 16382; + return; + } + #endif + // + + if (exp) exp -= 16383; + } + + + + void info::write_single(void *vp) const { + + using namespace single_traits; + + uint32_t i = 0; + + if (sign) i |= sign_bit; + + if (nan) { + // todo -- better signalling vs quiet... + i |= nan_exp; + i |= quiet_nan; // nan bit. + + unsigned tmp = sig & 0xff; + if (!tmp) tmp = 1; + i |= tmp; + } + else if (inf || exp > max_exp ) { + i |= nan_exp; // also infinite. + } + else if (exp < min_exp || !one) { + // todo -- could de-normalize here... + // if too small -> 0. + // no need to modify i! + } + else { + // de-normalized numbers handled above (as 0) + uint32_t e = exp + bias; + e <<= significand_bits; + i |= e; + + uint32_t s = sig >> (63 - significand_bits); + // and clear 1-bit + s &= significand_mask; + i |= s; + } + + std::memcpy(vp, &i, 4); + } + + void info::write_double(void *vp) const { + + using namespace double_traits; + + uint64_t i = 0; + + if (sign) i |= sign_bit; + + if (nan) { + // todo -- better signalling vs quiet... + i |= nan_exp; + i |= quiet_nan; // nan bit. + + unsigned tmp = sig & 0xff; + if (!tmp) tmp = 1; + i |= tmp; + } + else if (inf || exp > max_exp ) { + i |= nan_exp; + } + else if (exp < min_exp || !one) { + // if too small -> 0. + // no need to modify i! + } + else { + // de-normalized numbers handled above (as 0) + uint64_t e = exp + bias; + e <<= significand_bits; + i |= e; + + uint64_t s = sig >> (63 - significand_bits); + // and clear 1-bit + s &= significand_mask; + i |= s; + } + + std::memcpy(vp, &i, 8); + } + + void info::write_extended(void *vp) const { + //... + + using namespace extended_traits; + + uint64_t i = 0; + uint16_t sexp = 0; + + if (sign) sexp |= sign_bit; + + if (nan) { + // todo -- better signalling vs quiet... + sexp |= nan_exp; + i |= quiet_nan; // nan bit. + i |= one_bit; + + unsigned tmp = sig & 0xff; + if (!tmp) tmp = 1; + i |= tmp; + } + else if (inf || exp > max_exp ) { + sexp |= nan_exp; + i |= one_bit; + } + else if (exp < min_exp || !one) { + // if too small -> 0. + // no need to modify i! + } + else { + // de-normalized numbers handled above (as 0) + uint64_t e = exp + bias; + sexp |= e; + + i = sig; // 1-bit already set. + } + + uint8_t *cp = (uint8_t *)vp; + if (endian::native == endian::little) { + std::memcpy(cp + 0, &i, 8); + std::memcpy(cp + 8, &sexp, 2); + } else { + std::memcpy(cp + 0, &sexp, 2); + std::memcpy(cp + 2, &i, 8); + } + } + +} diff --git a/toolbox/floating_point.h b/toolbox/floating_point.h index 8902e7d..61fd878 100644 --- a/toolbox/floating_point.h +++ b/toolbox/floating_point.h @@ -9,426 +9,253 @@ //#include +//#include "endian.h" enum class endian { - big = 1234, - little = 3412, - native = little + little = 3412, + big = 1234, + native = little }; -namespace single_traits { - constexpr size_t bias = 127; - constexpr size_t exponent_bits = 8; - constexpr size_t significand_bits = 23; - constexpr int max_exp = 127; - constexpr int min_exp = -127; +namespace floating_point { - constexpr uint32_t significand_mask = ((1 << significand_bits) - 1); - constexpr uint32_t sign_bit = UINT32_C(1) << 31; - constexpr uint32_t nan_exp = UINT32_C(255) << significand_bits; + template + void reverse_bytes(void *vp) { + char *cp = (char *)vp; + for (size_t i = 0; i < size / 2; ++i) + std::swap(cp[i], cp[size - i - 1]); + } - constexpr uint32_t quiet_nan = UINT32_C(0x02) << (significand_bits - 2); - constexpr uint32_t signaling_nan = UINT32_C(0x01) << (significand_bits - 2); -} - -namespace double_traits { - constexpr size_t bias = 1023; - constexpr size_t exponent_bits = 11; - constexpr size_t significand_bits = 52; - constexpr int max_exp = 1023; - constexpr int min_exp = -1023; - - constexpr uint64_t significand_mask = ((UINT64_C(1) << significand_bits) - 1); - constexpr uint64_t sign_bit = UINT64_C(1) << 63; - constexpr uint64_t nan_exp = UINT64_C(2047) << significand_bits; - - constexpr uint64_t quiet_nan = UINT64_C(0x02) << (significand_bits - 2); - constexpr uint64_t signaling_nan = UINT64_C(0x01) << (significand_bits - 2); -} - -namespace extended_traits { - - constexpr size_t bias = 16383; - constexpr size_t exponent_bits = 15; - constexpr size_t significand_bits = 63; // does not include explicit 1. - constexpr int max_exp = 16383; - constexpr int min_exp = -16383; - - constexpr uint64_t significand_mask = ((UINT64_C(1) << significand_bits) - 1); - - constexpr uint64_t quiet_nan = UINT64_C(0x02) << (significand_bits - 2); - constexpr uint64_t signaling_nan = UINT64_C(0x01) << (significand_bits - 2); - - constexpr uint64_t one_bit = UINT64_C(0x8000000000000000); + template + void reverse_bytes_if(void *vp, std::true_type) { + reverse_bytes(vp); + } + template + void reverse_bytes_if(void *vp, std::false_type) { + } - // stored separately. - constexpr uint16_t sign_bit = 0x8000; - constexpr uint16_t nan_exp = 0x7fff; + namespace single_traits { + constexpr size_t bias = 127; + constexpr size_t exponent_bits = 8; + constexpr size_t significand_bits = 23; + constexpr int max_exp = 127; + constexpr int min_exp = -127; -} + constexpr uint32_t significand_mask = ((1 << significand_bits) - 1); + constexpr uint32_t sign_bit = UINT32_C(1) << 31; + constexpr uint32_t nan_exp = UINT32_C(255) << significand_bits; -class fpinfo { + constexpr uint32_t quiet_nan = UINT32_C(0x02) << (significand_bits - 2); + constexpr uint32_t signaling_nan = UINT32_C(0x01) << (significand_bits - 2); + } -public: + namespace double_traits { + constexpr size_t bias = 1023; + constexpr size_t exponent_bits = 11; + constexpr size_t significand_bits = 52; + constexpr int max_exp = 1023; + constexpr int min_exp = -1023; - bool sign = false; - bool one = false; - int exp = 0; - uint64_t sig = 0; // includes explicit 1 bit, adjusted to 63 bits of fraction. + constexpr uint64_t significand_mask = ((UINT64_C(1) << significand_bits) - 1); + constexpr uint64_t sign_bit = UINT64_C(1) << 63; + constexpr uint64_t nan_exp = UINT64_C(2047) << significand_bits; - bool nan = false; - bool inf = false; + constexpr uint64_t quiet_nan = UINT64_C(0x02) << (significand_bits - 2); + constexpr uint64_t signaling_nan = UINT64_C(0x01) << (significand_bits - 2); + } + + namespace extended_traits { + + constexpr size_t bias = 16383; + constexpr size_t exponent_bits = 15; + constexpr size_t significand_bits = 63; // does not include explicit 1. + constexpr int max_exp = 16383; + constexpr int min_exp = -16383; + + constexpr uint64_t significand_mask = ((UINT64_C(1) << significand_bits) - 1); + + constexpr uint64_t quiet_nan = UINT64_C(0x02) << (significand_bits - 2); + constexpr uint64_t signaling_nan = UINT64_C(0x01) << (significand_bits - 2); + + constexpr uint64_t one_bit = UINT64_C(0x8000000000000000); + // stored separately. + constexpr uint16_t sign_bit = 0x8000; + constexpr uint16_t nan_exp = 0x7fff; - template - fpinfo(void *data); + } - fpinfo(float f); - fpinfo(double d); - fpinfo(long double ld); - fpinfo() = default; - - template - void write(void *vp) const; - - - - void write(float &x) const; - void write(double &x) const; - void write(long double &x) const; - - -#if 0 - enum { - fp_zero, - fp_infinite, - fp_quiet_nan, - fp_signaling_nan, - fp_normal, - fp_subnormal + template + struct format { + static constexpr size_t size = _size; + static constexpr endian byte_order = _byte_order; }; -#endif -private: - //static constexpr uint64_t one_bit = UINT64_C(0x8000000000000000); - template void init(const void *vp); -}; + class info { + private: + void read_single(const void *); + void read_double(const void *); + void read_extended(const void *); -template<> -void fpinfo::init<4, endian::native>(const void *vp) { - uint32_t i; - std::memcpy(&i, vp, 4); + void write_single(void *) const; + void write_double(void *) const; + void write_extended(void *) const; + public: - sign = i >> 31; - one = 1; - exp = (i >> 23) & ((1 << 8) - 1); - sig = i & ((1 << 23) - 1); + bool sign = false; + bool one = false; + int exp = 0; + uint64_t sig = 0; // includes explicit 1 bit, adjusted to 63 bits of fraction. - if (exp == 255) { - exp = 0; - if (sig == 0) inf = true; - else { - nan = true; - sig &= ~(UINT64_C(1) << 22); + bool nan = false; + bool inf = false; + + + template::value> > + void read(T x) + { read(format{}, &x); } + + template + void read(format, const void *vp) { + + uint8_t buffer[size]; + static_assert(byte_order != endian::native, "byte order"); + + std::memcpy(buffer, vp, size); + reverse_bytes(buffer); + read(format{}, buffer); } - return; - } - if (exp == 0 && sig != 0) { - // denormalized. - one = 0; - sig <<= 40; //? - exp = -126; - return; - } - - if (exp) exp -= 127; // bias - - // adjust to 64 bit significand. - sig <<= 40; - if (one) sig |= (UINT64_C(1) << 63); -} - - -template<> -void fpinfo::init<8, endian::native>(const void *vp) { - - uint64_t i; - std::memcpy(&i, vp, 8); - - sign = i >> 63; - one = 1; - exp = (i >> 52) & ((1 << 11) - 1); - sig = i & ((UINT64_C(1) << 52) - 1); - - - if (exp == 2047) { - exp = 0; - if (sig == 0) inf = true; - else { - nan = true; - sig &= ~(UINT64_C(1) << 51); + void read(format<4, endian::native>, const void *vp) { + read_single(vp); } - return; - } - if (exp == 0 && sig != 0) { - // denormalized. - one = 0; - sig <<= 10; //? - exp = -1022; - return; - } - - if (exp) exp -= 1023; // bias - sig <<= 11; - if (one) sig |= (UINT64_C(1) << 63); -} -// read a macintosh extended... -template<> -void fpinfo::init<10, endian::big>(const void *vp) { - - -} - - -// some c compilers actually generate 128-bit floats.... -template<> -void fpinfo::init<16, endian::native>(const void *vp) { - - uint64_t i; - uint32_t sexp; - - if (endian::native == endian::little) { - std::memcpy(&i, (const uint8_t *)vp, 8); - std::memcpy(&sexp, (const uint8_t *)vp + 8, 4); - } else { - std::memcpy(&sexp, (const uint8_t *)vp + 4, 4); - std::memcpy(&i, (const uint8_t *)vp + 8, 8); - } - - sign = (sexp >> 15) & 0x01; - exp = sexp & ((1 << 15) - 1); - - one = i >> 63; - sig = i; // includes 1. i & ((UINT64_C(1) << 63) - 1); - - if (exp == 32767) { - exp = 0; - sig &= ((UINT64_C(1) << 63) - 1); - if (sig == 0) inf = true; - else { - nan = true; - sig &= ((UINT64_C(1) << 62) - 1); + void read(format<8, endian::native>, const void *vp) { + read_double(vp); } - return; - } - if (exp == 0 && sig != 0) { - // denormalized. - exp -= 16382; - return; - } + void read(format<10, endian::native>, const void *vp) { + read_extended(vp); + } - // + void read(format<12, endian::native>, const void *vp) { + // todo -- padding? + read_extended(vp); + } - if (exp) exp -= 16383; -} + void read(format<16, endian::native>, const void *vp) { + // todo -- padding? + read_extended(vp); + } -fpinfo::fpinfo(float x) { - init(&x); -} + template::value> > + void write(T &x) const + { write(format{}, &x); } -fpinfo::fpinfo(double x) { - init(&x); -} + template + void write(format, void *vp) const { + + uint8_t buffer[size]; + static_assert(byte_order != endian::native, "byte order"); -fpinfo::fpinfo(long double x) { - init(&x); -} + write(format{}, buffer); -//template void init(const void *vp); + reverse_bytes(buffer); + std::memcpy(vp, buffer, size); + } -template<> -void fpinfo::write<4, endian::native>(void *vp) const { - using namespace single_traits; + void write(format<4, endian::native>, void *vp) const { + write_single(vp); + } - uint32_t i = 0; - if (sign) i |= sign_bit; + void write(format<8, endian::native>, void *vp) const { + write_double(vp); + } - if (nan) { - // todo -- better signalling vs quiet... - i |= nan_exp; - i |= quiet_nan; // nan bit. + void write(format<10, endian::native>, void *vp) const { + write_extended(vp); + } - unsigned tmp = sig & 0xff; - if (!tmp) tmp = 1; - i |= tmp; - } - else if (inf || exp > max_exp ) { - i |= nan_exp; // also infinite. - } - else if (exp < min_exp || !one) { - // todo -- could de-normalize here... - // if too small -> 0. - // no need to modify i! - } - else { - // de-normalized numbers handled above (as 0) - uint32_t e = exp + bias; - e <<= significand_bits; - i |= e; + void write(format<12, endian::native>, void *vp) const { + // todo -- padding? + write_extended(vp); + std::memset((uint8_t *)vp + 10, 0, 12-10); + } - uint32_t s = sig >> (63 - significand_bits); - // and clear 1-bit - s &= significand_mask; - i |= s; - } - - std::memcpy(vp, &i, 4); -} + void write(format<16, endian::native>, void *vp) const { + // todo -- padding? + write_extended(vp); + std::memset((uint8_t *)vp + 10, 0, 16-10); + } -template<> -void fpinfo::write<8, endian::native>(void *vp) const { - using namespace double_traits; - uint64_t i = 0; + template::value> > + info(T x) { read(x); } + info() = default; - if (sign) i |= sign_bit; - if (nan) { - // todo -- better signalling vs quiet... - i |= nan_exp; - i |= quiet_nan; // nan bit. + #if 0 + enum { + fp_zero, + fp_infinite, + fp_quiet_nan, + fp_signaling_nan, + fp_normal, + fp_subnormal + }; + #endif - unsigned tmp = sig & 0xff; - if (!tmp) tmp = 1; - i |= tmp; - } - else if (inf || exp > max_exp ) { - i |= nan_exp; - } - else if (exp < min_exp || !one) { - // if too small -> 0. - // no need to modify i! - } - else { - // de-normalized numbers handled above (as 0) - uint64_t e = exp + bias; - e <<= significand_bits; - i |= e; - uint64_t s = sig >> (63 - significand_bits); - // and clear 1-bit - s &= significand_mask; - i |= s; - } + }; - std::memcpy(vp, &i, 8); -} - -template<> -void fpinfo::write<10, endian::big>(void *vp) const { - - using namespace extended_traits; - - uint64_t i = 0; - uint16_t sexp = 0; - - if (sign) sexp |= sign_bit; - - if (nan) { - // todo -- better signalling vs quiet... - sexp |= nan_exp; - i |= quiet_nan; // nan bit. - i |= one_bit; - - unsigned tmp = sig & 0xff; - if (!tmp) tmp = 1; - i |= tmp; - } - else if (inf || exp > max_exp ) { - sexp |= nan_exp; - i |= one_bit; - } - else if (exp < min_exp || !one) { - // if too small -> 0. - // no need to modify i! - } - else { - // de-normalized numbers handled above (as 0) - uint64_t e = exp + bias; - sexp |= e; - - i = sig; // 1-bit already set. - } - - std::memcpy(vp, &i, 10); -} - -template<> -void fpinfo::write<16, endian::native>(void *vp) const { -} - -void fpinfo::write(float &x) const { - write(&x); -} -void fpinfo::write(double &x) const { - write(&x); -} -void fpinfo::write(long double &x) const { - write(&x); -} - -namespace its_complicated { /* - std::string to_string(const fpinfo &fpi) + std::string to_string(const info &fpi) { } */ - inline int fpclassify(const fpinfo &fpi) { + inline int fpclassify(const info &fpi) { if (fpi.nan) return FP_NAN; if (fpi.inf) return FP_INFINITE; if (fpi.sig == 0) return FP_ZERO; return fpi.sig >> 63 ? FP_NORMAL : FP_SUBNORMAL; } - inline int signbit(const fpinfo &fpi) { + inline int signbit(const info &fpi) { return fpi.sign; } - inline int isnan(const fpinfo &fpi) { + inline int isnan(const info &fpi) { return fpi.nan; } - inline int isinf(const fpinfo &fpi) { + inline int isinf(const info &fpi) { return fpi.inf; } - inline int isfinite(const fpinfo &fpi) { + inline int isfinite(const info &fpi) { if (fpi.nan || fpi.inf) return false; return true; } - inline int isnormal(const fpinfo &fpi) { + inline int isnormal(const info &fpi) { if (fpi.nan || fpi.inf) return false; return fpi.sig >> 63; } + } - #endif diff --git a/unit_testing/floating_point.cpp b/unit_testing/floating_point.cpp index ba666f9..2253b37 100644 --- a/unit_testing/floating_point.cpp +++ b/unit_testing/floating_point.cpp @@ -1,30 +1,51 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" -#include "../toolbox/floating_point.h" +#include "floating_point.h" #include #include +namespace fp = floating_point; + + + +void bitdump(const void *vp, unsigned bytes) { + const uint8_t *p = (const uint8_t *)vp; + + p += bytes; + + for (unsigned i = 0; i < bytes; ++i) { + uint8_t c = *(--p); + for (int j = 0x80; j; j >>= 1) { + printf ("%d", c & j ? 1 : 0); + + } + printf(" "); + } + printf("\n"); +} + + TEST_CASE( "1.0 is handled", "[floating point info]") { - fpinfo fpi; + fp::info fpi; - fpi = fpinfo((float)1.0); + fpi = fp::info((float)1.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0x8000000000000000); - fpi = fpinfo((double)1.0); + fpi = fp::info((double)1.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0x8000000000000000); - fpi = fpinfo((long double)1.0); + fpi = fp::info((long double)1.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); @@ -35,23 +56,23 @@ TEST_CASE( "1.0 is handled", "[floating point info]") { TEST_CASE( "-1.0 is handled", "[floating point info]") { - fpinfo fpi; + fp::info fpi; - fpi = fpinfo((float)-1.0); + fpi = fp::info((float)-1.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 1); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0x8000000000000000); - fpi = fpinfo((double)-1.0); + fpi = fp::info((double)-1.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 1); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0x8000000000000000); - fpi = fpinfo((long double)-1.0); + fpi = fp::info((long double)-1.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 1); @@ -62,23 +83,23 @@ TEST_CASE( "-1.0 is handled", "[floating point info]") { TEST_CASE( "2.0 is handled", "[floating point info]") { - fpinfo fpi; + fp::info fpi; - fpi = fpinfo((float)2.0); + fpi = fp::info((float)2.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 1); REQUIRE(fpi.sig == 0x8000000000000000); - fpi = fpinfo((double)2.0); + fpi = fp::info((double)2.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 1); REQUIRE(fpi.sig == 0x8000000000000000); - fpi = fpinfo((long double)2.0); + fpi = fp::info((long double)2.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); @@ -89,23 +110,23 @@ TEST_CASE( "2.0 is handled", "[floating point info]") { TEST_CASE( "NaN("") is handled", "[floating point info]") { - fpinfo fpi; + fp::info fpi; - fpi = fpinfo(nanf("")); + fpi = fp::info(nanf("")); REQUIRE(fpi.nan == true); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0x0000000000000000); - fpi = fpinfo(nan("")); + fpi = fp::info(nan("")); REQUIRE(fpi.nan == true); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0x0000000000000000); - fpi = fpinfo(nanl("")); + fpi = fp::info(nanl("")); REQUIRE(fpi.nan == true); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); @@ -116,23 +137,23 @@ TEST_CASE( "NaN("") is handled", "[floating point info]") { TEST_CASE( "NaN(255) is handled", "[floating point info]") { - fpinfo fpi; + fp::info fpi; - fpi = fpinfo(nanf("255")); + fpi = fp::info(nanf("255")); REQUIRE(fpi.nan == true); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 255); - fpi = fpinfo(nan("255")); + fpi = fp::info(nan("255")); REQUIRE(fpi.nan == true); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 255); - fpi = fpinfo(nanl("255")); + fpi = fp::info(nanl("255")); REQUIRE(fpi.nan == true); REQUIRE(fpi.inf == false); REQUIRE(fpi.sign == 0); @@ -143,23 +164,23 @@ TEST_CASE( "NaN(255) is handled", "[floating point info]") { TEST_CASE( "Inf is handled", "[floating point info]") { - fpinfo fpi; + fp::info fpi; - fpi = fpinfo((float)1.0/0.0); + fpi = fp::info((float)1.0/0.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == true); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0); - fpi = fpinfo((double)1.0/0.0); + fpi = fp::info((double)1.0/0.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == true); REQUIRE(fpi.sign == 0); REQUIRE(fpi.exp == 0); REQUIRE(fpi.sig == 0); - fpi = fpinfo((long double)1.0/0.0); + fpi = fp::info((long double)1.0/0.0); REQUIRE(fpi.nan == false); REQUIRE(fpi.inf == true); REQUIRE(fpi.sign == 0); @@ -173,17 +194,20 @@ TEST_CASE( "Re-cast 0.0", "[floating point info]") { float target_f = 0.0; double target_d = 0.0; double target_ld = 0.0; + long double ld; double d; float f; - fpinfo fpi(0.0l); + fp::info fpi(0.0l); fpi.write(f); fpi.write(d); + fpi.write(ld); REQUIRE(memcmp(&target_f, &f, sizeof(f)) == 0); REQUIRE(memcmp(&target_d, &d, sizeof(d)) == 0); + REQUIRE(memcmp(&target_ld, &ld, sizeof(ld)) == 0); } @@ -192,17 +216,20 @@ TEST_CASE( "Re-cast 1.0", "[floating point info]") { float target_f = 1.0; double target_d = 1.0; double target_ld = 1.0; + long double ld; double d; float f; - fpinfo fpi(1.0l); + fp::info fpi(1.0l); fpi.write(f); fpi.write(d); + fpi.write(ld); REQUIRE(memcmp(&target_f, &f, sizeof(f)) == 0); REQUIRE(memcmp(&target_d, &d, sizeof(d)) == 0); + REQUIRE(memcmp(&target_ld, &ld, sizeof(ld)) == 0); } @@ -211,17 +238,20 @@ TEST_CASE( "Re-cast -1.0", "[floating point info]") { float target_f = -1.0; double target_d = -1.0; double target_ld = -1.0; + long double ld; double d; float f; - fpinfo fpi(-1.0l); + fp::info fpi(-1.0l); fpi.write(f); fpi.write(d); + fpi.write(ld); REQUIRE(memcmp(&target_f, &f, sizeof(f)) == 0); REQUIRE(memcmp(&target_d, &d, sizeof(d)) == 0); + REQUIRE(memcmp(&target_ld, &ld, sizeof(ld)) == 0); } @@ -231,17 +261,20 @@ TEST_CASE( "Re-cast 1000.0", "[floating point info]") { float target_f = 1000.0; double target_d = 1000.0; double target_ld = 1000.0; + long double ld; double d; float f; - fpinfo fpi(1000.0l); + fp::info fpi(1000.0l); fpi.write(f); fpi.write(d); + fpi.write(ld); REQUIRE(memcmp(&target_f, &f, sizeof(f)) == 0); REQUIRE(memcmp(&target_d, &d, sizeof(d)) == 0); + REQUIRE(memcmp(&target_ld, &ld, sizeof(ld)) == 0); } @@ -251,17 +284,20 @@ TEST_CASE( "Re-cast Inf", "[floating point info]") { float target_f = 1.0/0.0; double target_d = 1.0/0.0; double target_ld = 1.0/0.0; + long double ld; double d; float f; - fpinfo fpi(1.0/0.0l); + fp::info fpi(1.0/0.0l); fpi.write(f); fpi.write(d); + fpi.write(ld); REQUIRE(memcmp(&target_f, &f, sizeof(f)) == 0); REQUIRE(memcmp(&target_d, &d, sizeof(d)) == 0); + REQUIRE(memcmp(&target_ld, &ld, sizeof(ld)) == 0); } @@ -270,15 +306,18 @@ TEST_CASE( "Re-cast NaN", "[floating point info]") { float target_f = nanf("16"); double target_d = nan("16"); double target_ld = nanl("16"); + long double ld; double d; float f; - fpinfo fpi(nanl("16")); + fp::info fpi(nanl("16")); fpi.write(f); fpi.write(d); + fpi.write(ld); REQUIRE(memcmp(&target_f, &f, sizeof(f)) == 0); REQUIRE(memcmp(&target_d, &d, sizeof(d)) == 0); + REQUIRE(memcmp(&target_ld, &ld, sizeof(ld)) == 0); }