libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers float_spec.hpp Source File

float_spec.hpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #ifndef UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED
00006 #define UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED
00007 
00008 #include <cmath>
00009 #include <uavcan/std.hpp>
00010 #include <uavcan/data_type.hpp>
00011 #include <uavcan/util/templates.hpp>
00012 #include <uavcan/build_config.hpp>
00013 #include <uavcan/marshal/type_util.hpp>
00014 #include <uavcan/marshal/integer_spec.hpp>
00015 
00016 #ifndef UAVCAN_CPP_VERSION
00017 # error UAVCAN_CPP_VERSION
00018 #endif
00019 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00020 # include <limits>     // Assuming that in C++11 mode all standard headers are available
00021 #endif
00022 
00023 namespace uavcan
00024 {
00025 
00026 template <unsigned BitLen>
00027 struct NativeFloatSelector
00028 {
00029     struct ErrorNoSuchFloat;
00030     typedef typename Select<(sizeof(float) * 8 >= BitLen), float,
00031             typename Select<(sizeof(double) * 8 >= BitLen), double,
00032             typename Select<(sizeof(long double) * 8 >= BitLen), long double,
00033                               ErrorNoSuchFloat>::Result>::Result>::Result Type;
00034 };
00035 
00036 
00037 class UAVCAN_EXPORT IEEE754Converter
00038 {
00039     // TODO: Non-IEEE float support
00040 
00041     static uint16_t nativeIeeeToHalf(float value);
00042     static float halfToNativeIeee(uint16_t value);
00043 
00044     IEEE754Converter();
00045 
00046     template <unsigned BitLen>
00047     static void enforceIeee()
00048     {
00049         /*
00050          * Some compilers may have is_iec559 to be defined false despite the fact that IEEE754 is supported.
00051          * An acceptable workaround would be to put an #ifdef here.
00052          */
00053 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00054         StaticAssert<std::numeric_limits<typename NativeFloatSelector<BitLen>::Type>::is_iec559>::check();
00055 #endif
00056     }
00057 
00058 public:
00059 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00060     /// UAVCAN requires rounding to nearest for all float conversions
00061     static std::float_round_style roundstyle() { return std::round_to_nearest; }
00062 #endif
00063 
00064     template <unsigned BitLen>
00065     static typename IntegerSpec<BitLen, SignednessUnsigned, CastModeTruncate>::StorageType
00066     toIeee(typename NativeFloatSelector<BitLen>::Type value)
00067     {
00068         enforceIeee<BitLen>();
00069         union
00070         {
00071             typename IntegerSpec<BitLen, SignednessUnsigned, CastModeTruncate>::StorageType i;
00072             typename NativeFloatSelector<BitLen>::Type f;
00073         } u;
00074         StaticAssert<sizeof(u.f) * 8 == BitLen>::check();
00075         u.f = value;
00076         return u.i;
00077     }
00078 
00079     template <unsigned BitLen>
00080     static typename NativeFloatSelector<BitLen>::Type
00081     toNative(typename IntegerSpec<BitLen, SignednessUnsigned, CastModeTruncate>::StorageType value)
00082     {
00083         enforceIeee<BitLen>();
00084         union
00085         {
00086             typename IntegerSpec<BitLen, SignednessUnsigned, CastModeTruncate>::StorageType i;
00087             typename NativeFloatSelector<BitLen>::Type f;
00088         } u;
00089         StaticAssert<sizeof(u.f) * 8 == BitLen>::check();
00090         u.i = value;
00091         return u.f;
00092     }
00093 };
00094 template <>
00095 inline typename IntegerSpec<16, SignednessUnsigned, CastModeTruncate>::StorageType
00096 IEEE754Converter::toIeee<16>(typename NativeFloatSelector<16>::Type value)
00097 {
00098     return nativeIeeeToHalf(value);
00099 }
00100 template <>
00101 inline typename NativeFloatSelector<16>::Type
00102 IEEE754Converter::toNative<16>(typename IntegerSpec<16, SignednessUnsigned, CastModeTruncate>::StorageType value)
00103 {
00104     return halfToNativeIeee(value);
00105 }
00106 
00107 
00108 template <unsigned BitLen> struct IEEE754Limits;
00109 template <> struct IEEE754Limits<16>
00110 {
00111     typedef typename NativeFloatSelector<16>::Type NativeType;
00112     static NativeType max() { return static_cast<NativeType>(65504.0); }
00113     static NativeType epsilon() { return static_cast<NativeType>(9.77e-04); }
00114 };
00115 template <> struct IEEE754Limits<32>
00116 {
00117     typedef typename NativeFloatSelector<32>::Type NativeType;
00118     static NativeType max() { return static_cast<NativeType>(3.40282346638528859812e+38); }
00119     static NativeType epsilon() { return static_cast<NativeType>(1.19209289550781250000e-7); }
00120 };
00121 template <> struct IEEE754Limits<64>
00122 {
00123     typedef typename NativeFloatSelector<64>::Type NativeType;
00124     static NativeType max() { return static_cast<NativeType>(1.79769313486231570815e+308L); }
00125     static NativeType epsilon() { return static_cast<NativeType>(2.22044604925031308085e-16L); }
00126 };
00127 
00128 
00129 template <unsigned BitLen_, CastMode CastMode>
00130 class UAVCAN_EXPORT FloatSpec : public IEEE754Limits<BitLen_>
00131 {
00132     FloatSpec();
00133 
00134 public:
00135     enum { BitLen = BitLen_ };
00136     enum { MinBitLen = BitLen };
00137     enum { MaxBitLen = BitLen };
00138     enum { IsPrimitive = 1 };
00139 
00140     typedef typename NativeFloatSelector<BitLen>::Type StorageType;
00141 
00142 #if UAVCAN_CPP_VERSION < UAVCAN_CPP11
00143     enum { IsExactRepresentation = (sizeof(StorageType) * 8 == BitLen) };
00144 #else
00145     enum { IsExactRepresentation = (sizeof(StorageType) * 8 == BitLen) && std::numeric_limits<StorageType>::is_iec559 };
00146 #endif
00147 
00148     using IEEE754Limits<BitLen>::max;
00149     using IEEE754Limits<BitLen>::epsilon;
00150 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
00151     static std::float_round_style roundstyle() { return IEEE754Converter::roundstyle(); }
00152 #endif
00153 
00154     static int encode(StorageType value, ScalarCodec& codec, TailArrayOptimizationMode)
00155     {
00156         // cppcheck-suppress duplicateExpression
00157         if (CastMode == CastModeSaturate)
00158         {
00159             saturate(value);
00160         }
00161         else
00162         {
00163             truncate(value);
00164         }
00165         return codec.encode<BitLen>(IEEE754Converter::toIeee<BitLen>(value));
00166     }
00167 
00168     static int decode(StorageType& out_value, ScalarCodec& codec, TailArrayOptimizationMode)
00169     {
00170         typename IntegerSpec<BitLen, SignednessUnsigned, CastModeTruncate>::StorageType ieee = 0;
00171         const int res = codec.decode<BitLen>(ieee);
00172         if (res <= 0)
00173         {
00174             return res;
00175         }
00176         out_value = IEEE754Converter::toNative<BitLen>(ieee);
00177         return res;
00178     }
00179 
00180     static void extendDataTypeSignature(DataTypeSignature&) { }
00181 
00182 private:
00183     static inline void saturate(StorageType& value)
00184     {
00185         if ((IsExactRepresentation == 0) && isFinite(value))
00186         {
00187             if (value > max())
00188             {
00189                 value = max();
00190             }
00191             else if (value < -max())
00192             {
00193                 value = -max();
00194             }
00195             else
00196             {
00197                 ; // Valid range
00198             }
00199         }
00200     }
00201 
00202     static inline void truncate(StorageType& value)
00203     {
00204         if ((IsExactRepresentation == 0) && isFinite(value))
00205         {
00206             if (value > max())
00207             {
00208                 value = NumericTraits<StorageType>::infinity();
00209             }
00210             else if (value < -max())
00211             {
00212                 value = -NumericTraits<StorageType>::infinity();
00213             }
00214             else
00215             {
00216                 ; // Valid range
00217             }
00218         }
00219     }
00220 };
00221 
00222 
00223 template <unsigned BitLen, CastMode CastMode>
00224 class UAVCAN_EXPORT YamlStreamer<FloatSpec<BitLen, CastMode> >
00225 {
00226     typedef typename FloatSpec<BitLen, CastMode>::StorageType StorageType;
00227 
00228 public:
00229     template <typename Stream>  // cppcheck-suppress passedByValue
00230     static void stream(Stream& s, const StorageType value, int)
00231     {
00232         s << value;
00233     }
00234 };
00235 
00236 }
00237 
00238 #endif // UAVCAN_MARSHAL_FLOAT_SPEC_HPP_INCLUDED