/* * Copyright (C) 2014 Pavel Kirienko */ #ifndef UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED #define UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED #include #include #include #include #include #include #include #ifndef UAVCAN_CPP_VERSION # error UAVCAN_CPP_VERSION #endif #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 # include // Assuming that in C++11 mode all standard headers are available #endif namespace uavcan { template struct NativeFloatSelector { struct ErrorNoSuchFloat; typedef typename Select<(sizeof(float) * 8 >= BitLen), float, typename Select<(sizeof(double) * 8 >= BitLen), double, typename Select<(sizeof(long double) * 8 >= BitLen), long double, ErrorNoSuchFloat>::Result>::Result>::Result Type; }; class UAVCAN_EXPORT IEEE754Converter { // TODO: Non-IEEE float support for float32 and float64 static uint16_t nativeNonIeeeToHalf(float value); static float halfToNativeNonIeee(uint16_t value); IEEE754Converter(); public: #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 /// UAVCAN requires rounding to nearest for all float conversions static std::float_round_style roundstyle() { return std::round_to_nearest; } #endif template static typename IntegerSpec::StorageType toIeee(typename NativeFloatSelector::Type value) { union { typename IntegerSpec::StorageType i; typename NativeFloatSelector::Type f; } u; StaticAssert::check(); u.f = value; return u.i; } template static typename NativeFloatSelector::Type toNative(typename IntegerSpec::StorageType value) { union { typename IntegerSpec::StorageType i; typename NativeFloatSelector::Type f; } u; StaticAssert::check(); u.i = value; return u.f; } }; template <> inline typename IntegerSpec<16, SignednessUnsigned, CastModeTruncate>::StorageType IEEE754Converter::toIeee<16>(typename NativeFloatSelector<16>::Type value) { return nativeNonIeeeToHalf(value); } template <> inline typename NativeFloatSelector<16>::Type IEEE754Converter::toNative<16>(typename IntegerSpec<16, SignednessUnsigned, CastModeTruncate>::StorageType value) { return halfToNativeNonIeee(value); } template struct IEEE754Limits; template <> struct IEEE754Limits<16> { typedef typename NativeFloatSelector<16>::Type NativeType; static NativeType max() { return static_cast(65504.0); } static NativeType epsilon() { return static_cast(9.77e-04); } }; template <> struct IEEE754Limits<32> { typedef typename NativeFloatSelector<32>::Type NativeType; static NativeType max() { return static_cast(3.40282346638528859812e+38); } static NativeType epsilon() { return static_cast(1.19209289550781250000e-7); } }; template <> struct IEEE754Limits<64> { typedef typename NativeFloatSelector<64>::Type NativeType; static NativeType max() { return static_cast(1.79769313486231570815e+308L); } static NativeType epsilon() { return static_cast(2.22044604925031308085e-16L); } }; template class UAVCAN_EXPORT FloatSpec : public IEEE754Limits { FloatSpec(); public: enum { BitLen = BitLen_ }; enum { MinBitLen = BitLen }; enum { MaxBitLen = BitLen }; enum { IsPrimitive = 1 }; typedef typename NativeFloatSelector::Type StorageType; #if UAVCAN_CPP_VERSION < UAVCAN_CPP11 enum { IsExactRepresentation = (sizeof(StorageType) * 8 == BitLen) }; #else enum { IsExactRepresentation = (sizeof(StorageType) * 8 == BitLen) && std::numeric_limits::is_iec559 }; #endif using IEEE754Limits::max; using IEEE754Limits::epsilon; #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11 static std::float_round_style roundstyle() { return IEEE754Converter::roundstyle(); } #endif static int encode(StorageType value, ScalarCodec& codec, TailArrayOptimizationMode) { // cppcheck-suppress duplicateExpression if (CastMode == CastModeSaturate) { saturate(value); } else { truncate(value); } return codec.encode(IEEE754Converter::toIeee(value)); } static int decode(StorageType& out_value, ScalarCodec& codec, TailArrayOptimizationMode) { typename IntegerSpec::StorageType ieee = 0; const int res = codec.decode(ieee); if (res <= 0) { return res; } out_value = IEEE754Converter::toNative(ieee); return res; } static void extendDataTypeSignature(DataTypeSignature&) { } private: static inline void saturate(StorageType& value) { if ((IsExactRepresentation == 0) && isFinite(value)) { if (value > max()) { value = max(); } else if (value < -max()) { value = -max(); } else { ; // Valid range } } } static inline void truncate(StorageType& value) { if ((IsExactRepresentation == 0) && isFinite(value)) { if (value > max()) { value = NumericTraits::infinity(); } else if (value < -max()) { value = -NumericTraits::infinity(); } else { ; // Valid range } } } }; template class UAVCAN_EXPORT YamlStreamer > { typedef typename FloatSpec::StorageType StorageType; public: template // cppcheck-suppress passedByValue static void stream(Stream& s, const StorageType value, int) { s << value; } }; } #endif // UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED