From 9d302c5dcc949da8916a6f03d248c9e429753de1 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Tue, 9 Aug 2016 13:29:07 -0400 Subject: [PATCH] clean up fpinfo a little bit. --- include/endian.h | 27 +++++++- toolbox/fpinfo.cpp | 152 ++++++++++++++++++++++++++++++++++++++++++++- toolbox/fpinfo.h | 24 +++---- toolbox/sane.cpp | 4 +- 4 files changed, 190 insertions(+), 17 deletions(-) diff --git a/include/endian.h b/include/endian.h index 96e4bbf..b381149 100644 --- a/include/endian.h +++ b/include/endian.h @@ -21,7 +21,7 @@ #define bswap32 __builtin_bswap32 #define bswap64 __builtin_bswap64 -#if _BYTE_ORDER == _LITTLE_ENDIAN +#if BYTE_ORDER == LITTLE_ENDIAN #define htobe16(x) bswap16((x)) #define htobe32(x) bswap32((x)) #define htobe64(x) bswap64((x)) @@ -35,7 +35,7 @@ #define le16toh(x) ((uint16_t)(x)) #define le32toh(x) ((uint32_t)(x)) #define le64toh(x) ((uint64_t)(x)) -#else /* _BYTE_ORDER != _LITTLE_ENDIAN */ +#else /* BYTE_ORDER != LITTLE_ENDIAN */ #define htobe16(x) ((uint16_t)(x)) #define htobe32(x) ((uint32_t)(x)) #define htobe64(x) ((uint64_t)(x)) @@ -49,7 +49,28 @@ #define le16toh(x) bswap16((x)) #define le32toh(x) bswap32((x)) #define le64toh(x) bswap64((x)) -#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */ +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + +#endif + + +#ifdef __cplusplus + +// https://github.com/HowardHinnant/hash_append/blob/master/endian.h +enum class endian +{ + native = LITTLE_ENDIAN, + little = LITTLE_ENDIAN, + big = BIG_ENDIAN +}; + +static_assert(endian::native == endian::little || + endian::native == endian::big, + "endian::native shall be one of endian::little or endian::big"); + +static_assert(endian::big != endian::little, + "endian::big and endian::little shall have different values"); + #endif diff --git a/toolbox/fpinfo.cpp b/toolbox/fpinfo.cpp index a0da142..1e00286 100644 --- a/toolbox/fpinfo.cpp +++ b/toolbox/fpinfo.cpp @@ -7,6 +7,154 @@ static_assert(sizeof(float) == 4, "Unexpected float size"); static_assert(sizeof(double) == 8, "Unexpected double size"); static_assert(sizeof(long double) == 8 || sizeof(long double) == 12 || sizeof(long double) == 16, "Unexpected long double size"); + +namespace { + + + template + void init(const void *vp, fpinfo &info); + + // 32-bit float + template<> + void init<4>(const void *vp, fpinfo &info) { + + + uint32_t i = *(uint32_t *)vp; + + info.sign = i >> 31; + info.one = 1; + info.exp = (i >> 23) & ((1 << 8) - 1); + info.sig = i & ((1 << 24) - 1); + + if (info.exp == 255) { + if (info.sig == 0) info.inf = true; + else info.nan = true; + return; + } + + if (info.exp == 0) { + // 0 or denormalized. + info.one = 0; + info.exp = -126; + return; + } + + info.exp -= 127; // bias + } + + // 64-bit double or long double. + template<> + void init<8>(const void *vp, fpinfo &info) { + + uint64_t i = *(uint64_t *)vp; + + info.sign = i >> 63; + info.one = 1; + info.exp = (i >> 52) & ((1 << 11) - 1); + info.sig = i & ((UINT64_C(1) << 53) - 1); + + + if (info.exp == 2047) { + if (info.sig == 0) info.inf = true; + else info.nan = true; + return; + } + + if (info.exp == 0) { + // 0 or denormalized. + info.one = 0; + info.exp = -1022; + return; + } + + info.exp -= 1023; // bias + } + + /* solaris - 96-bit long double. */ + template<> + void init<12>(const void *vp, fpinfo &info) { + + + uint64_t i; + uint32_t sexp; + + + // this needs to be verified. + #if BYTE_ORDER == LITTLE_ENDIAN + i = ((uint64_t *)vp)[0]; + sexp = ((uint32_t *)vp)[2] & 0xffff; + #else + #error "please verify big-endian long double format." + sexp = *((uint32_t *)vp) & 0xffff; + i = *((uint64_t *)((uint8_t *)vp+4); + #endif + + info.sign = (sexp >> 15) & 0x01; + info.exp = sexp & ((1 << 15) - 1); + + info.one = i >> 63; + info.sig = i & ((UINT64_C(1) << 63) - 1); + + if (info.exp == 32767) { + if (info.sig == 0) info.inf = true; + else info.nan = true; + return; + } + // + + info.exp -= 16383; + + } + + /* 128-bit long double. same format as 96 but extra padding */ + template<> + void init<16>(const void *vp, fpinfo &info) { + + uint64_t i; + uint32_t sexp; + + + // this needs to be verified. + #if BYTE_ORDER == LITTLE_ENDIAN + i = ((uint64_t *)vp)[0]; + sexp = ((uint32_t *)vp)[2] & 0xffff; + #else + #error "please verify big-endian long double format." + i = ((uint64_t *)vp)[1]; + sexp = ((uint64_t *)vp)[0] & 0xffff; + #endif + + info.sign = (sexp >> 15) & 0x01; + info.exp = sexp & ((1 << 15) - 1); + + info.one = i >> 63; + info.sig = i & ((UINT64_C(1) << 63) - 1); + + if (info.exp == 32767) { + if (info.sig == 0) info.inf = true; + else info.nan = true; + return; + } + // + + info.exp -= 16383; + } + + +} + +fpinfo::fpinfo(const float &f) { + init(&f, *this); +} +fpinfo::fpinfo(const double &d) { + init(&d, *this); + +} +fpinfo::fpinfo(const long double &ld) { + init(&ld, *this); +} + +#if 0 void fpinfo::init(float *f) { union split { @@ -103,4 +251,6 @@ void fpinfo::init(long double *ld) // exp -= 16383; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/toolbox/fpinfo.h b/toolbox/fpinfo.h index 4355ab8..896005e 100644 --- a/toolbox/fpinfo.h +++ b/toolbox/fpinfo.h @@ -4,6 +4,16 @@ #include struct fpinfo { + +private: + /* + void init(float *); + void init(double *); + void init(long double *); + */ + +public: + bool sign = false; bool one = false; int exp = 0; @@ -12,17 +22,9 @@ struct fpinfo { bool nan = false; bool inf = false; - fpinfo(float f) { init(&f); } - fpinfo(double d) { init(&d); } - fpinfo(long double ld) { - if (sizeof(long double) == 16 || sizeof(long double) == 12) init(&ld); - if (sizeof(long double) == 8) init((double *)&ld); - } - -private: - void init(float *); - void init(double *); - void init(long double *); + fpinfo(const float &f); + fpinfo(const double &d); + fpinfo(const long double &ld); }; diff --git a/toolbox/sane.cpp b/toolbox/sane.cpp index 369874a..596d7e3 100644 --- a/toolbox/sane.cpp +++ b/toolbox/sane.cpp @@ -167,7 +167,7 @@ using its_complicated::signbit; template<> long double readnum(uint32_t address) { - char buffer[16]; + uint8_t buffer[16]; static_assert(sizeof(long double) == 16 || sizeof(long double) == 12, "unexpected long double size"); @@ -237,7 +237,7 @@ using its_complicated::signbit; { static_assert(sizeof(value) == 16 || sizeof(value) == 12, "unexpected long double size"); - char buffer[16]; + uint8_t buffer[16]; std::memcpy(buffer, &value, sizeof(value));