libuav original
Dependents: UAVCAN UAVCAN_Subscriber
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
Generated on Tue Jul 12 2022 17:17:31 by 1.7.2