diff --git a/LCS/Common/include/Common/Numeric.h b/LCS/Common/include/Common/Numeric.h index c549004175c2bfa48d5bca7fed01d0e3a5bc3a3e..3d82558ccf3f878955c554041ff4e0195c6c05b0 100644 --- a/LCS/Common/include/Common/Numeric.h +++ b/LCS/Common/include/Common/Numeric.h @@ -56,12 +56,25 @@ namespace LOFAR // check this at compile-time. class Numeric { + private: + // termplate for masking one type with another + template <typename T, typename M> union maskUnion { + T value; + M mask; + }; + public: // Mask type used for floats is a (32-bit) int. typedef int floatMask_t; // Mask type used for doubles is a (64-bit) long long. typedef long long doubleMask_t; + // @{ + // Classes to overlap floating point numbers with masks in a type-safe way + typedef maskUnion<float,floatMask_t> floatUnion_t; + typedef maskUnion<double,doubleMask_t> doubleUnion_t; + // @} + // \return \c true if f < 0; otherwise \c false. static bool isNegative(float f); // \return \c true if d < 0; otherwise \c false. @@ -106,16 +119,6 @@ namespace LOFAR static const doubleMask_t doubleMantissaMask = 0x000FFFFFFFFFFFFFLL; // @} - // @{ - // Classes to overlap floating point numbers with masks in a type-safe way - template <typename T, typename M> union maskUnion { - T value; - M mask; - }; - - typedef maskUnion<float,floatMask_t> floatUnion; - typedef maskUnion<double,doubleMask_t> doubleUnion; - // @} }; } // namespace LOFAR diff --git a/LCS/Common/src/Numeric.cc b/LCS/Common/src/Numeric.cc index 58fc1dfc4b92aa691ccabfd9200ab28195f41332..4fc15aa3269c3a6bd323917acb351398da7f25e4 100644 --- a/LCS/Common/src/Numeric.cc +++ b/LCS/Common/src/Numeric.cc @@ -32,49 +32,49 @@ namespace LOFAR { bool Numeric::isFinite(float f) { - floatUnion mask = { f }; + floatUnion_t mask = { f }; return mask.mask & floatExponentMask != floatExponentMask; } bool Numeric::isFinite(double d) { - doubleUnion mask = { d }; + doubleUnion_t mask = { d }; return mask.mask & doubleExponentMask != doubleExponentMask; } bool Numeric::isNegative(float f) { - floatUnion mask = { f }; + floatUnion_t mask = { f }; return mask.mask & floatNegativeMask == floatNegativeMask; } bool Numeric::isNegative(double d) { - doubleUnion mask = { d }; + doubleUnion_t mask = { d }; return mask.mask & doubleNegativeMask == doubleNegativeMask; } bool Numeric::isInf(float f) { - floatUnion mask = { f }; + floatUnion_t mask = { f }; return !isFinite(f) && (mask.mask & floatMantissaMask == 0L); } bool Numeric::isInf(double d) { - doubleUnion mask = { d }; + doubleUnion_t mask = { d }; return !isFinite(d) && (mask.mask & doubleMantissaMask == 0LL); } bool Numeric::isNan(float f) { - floatUnion mask = { f }; + floatUnion_t mask = { f }; return !isFinite(f) && (mask.mask & floatMantissaMask != 0L); } bool Numeric::isNan(double d) { - doubleUnion mask = { d }; + doubleUnion_t mask = { d }; return !isFinite(d) && (mask.mask & doubleMantissaMask != 0LL); } @@ -101,8 +101,8 @@ namespace LOFAR if (isNegative(lhs) != isNegative(rhs)) return lhs == rhs; #endif - floatUnion mlhs = { lhs }; - floatUnion mrhs = { rhs }; + floatUnion_t mlhs = { lhs }; + floatUnion_t mrhs = { rhs }; floatMask_t ilhs = mlhs.mask; floatMask_t irhs = mrhs.mask; @@ -140,8 +140,8 @@ namespace LOFAR if (isNegative(lhs) != isNegative(rhs)) return lhs == rhs; #endif - doubleUnion mlhs = { lhs }; - doubleUnion mrhs = { rhs }; + doubleUnion_t mlhs = { lhs }; + doubleUnion_t mrhs = { rhs }; doubleMask_t ilhs = mlhs.mask; doubleMask_t irhs = mrhs.mask; diff --git a/LCS/Common/test/tNumeric.cc b/LCS/Common/test/tNumeric.cc index 5bc0ff7c4540e890419c68b10e3e94f2ea1129c8..cd7e51a2e86ae05b1cf27feb115924c162bebb07 100644 --- a/LCS/Common/test/tNumeric.cc +++ b/LCS/Common/test/tNumeric.cc @@ -37,11 +37,13 @@ using namespace std; #define initNumbers(T) \ LOG_INFO("initNumbers("#T")"); \ typedef Numeric::T##Mask_t mask_t; \ + typedef Numeric::T##Union_t union_t; \ ASSERT(sizeof(T) == sizeof(mask_t)); \ T zero(0), one(1), two(2); \ /* Create a negative zero */ \ - T negativeZero; \ - *(mask_t*)&negativeZero = mask_t(1) << 8*sizeof(T)-1; \ + union_t negativeZero_u; \ + negativeZero_u.mask = mask_t(1) << 8*sizeof(T)-1; \ + T negativeZero(negativeZero_u.value); \ /* Create an infinity */ \ T inf(one/zero); \ /* Create a NaN */ \ @@ -54,27 +56,33 @@ using namespace std; T nan4(sqrt(-one)); \ /* Copy one of the NANs and modify its representation. */ \ /* This will still give a NAN, just a different one. */ \ - T nan5(nan1); \ - (*(mask_t*)&nan5) += 1; \ + union_t nan5_u = { nan1 }; \ + nan5_u.mask += 1; \ + T nan5(nan5_u.value); \ /* Create number nearest to 2 (1 ULP below) */ \ - T nearestTwo(two); \ - (*(mask_t*)&nearestTwo) -= 1; \ + union_t nearestTwo_u = { two }; \ + nearestTwo_u.mask -= 1; \ + T nearestTwo(nearestTwo_u.value); \ /* Create a number near to 2 (sizeof(T) ULPs below) */ \ - T nearTwo(two); \ - (*(mask_t*)&nearTwo) -= sizeof(T); \ + union_t nearTwo_u = { two }; \ + nearTwo_u.mask -= sizeof(T); \ + T nearTwo(nearTwo_u.value); \ /* Create a number not so near to 2 (sizeof(T)^2 ULPs below) */ \ - T notNearTwo(two); \ - (*(mask_t*)¬NearTwo) -= sizeof(T)*sizeof(T); \ + union_t notNearTwo_u = { two }; \ + notNearTwo_u.mask -= sizeof(T)*sizeof(T); \ + T notNearTwo(notNearTwo_u.value); \ /* Create a denormal by starting with zero and */ \ /* incrementing the integer representation. */ \ - T smallestDenormal(0); \ - (*(mask_t*)&smallestDenormal) += 1; + union_t smallestDenormal_u = { zero }; \ + smallestDenormal_u.mask += 1; \ + T smallestDenormal(smallestDenormal_u.value); #define printNumber(os, x) \ { int p(2*sizeof(x)+1); \ + union_t u = { x }; \ os << setprecision(p) << left << setw(17) << #x << " = " \ << setw(p+6) << x << " (" << hex << showbase << setw(p+1) \ - << *(mask_t*)&x << dec << ")" << endl; \ + << u.value << dec << ")" << endl; \ } #define showNumbers(T) \ { LOG_INFO("showNumbers("#T")"); \ @@ -234,8 +242,11 @@ void testFloat() float pinf(one/zero); float ninf(none/zero); float nan(pinf/pinf); - long ione(1); - float pdmin(*(float*)(&ione)); // smallest denormalized float + union { + long ione; + float fone; + } u = { 1 }; + float pdmin(u.fone); // smallest denormalized float float ndmin(-pdmin); ASSERT(!Numeric::isNegative(zero));