diff --git a/DataStructures/FixedPointNumber.h b/DataStructures/FixedPointNumber.h new file mode 100644 index 000000000..fe718c38f --- /dev/null +++ b/DataStructures/FixedPointNumber.h @@ -0,0 +1,199 @@ +/* + +Copyright (c) 2013, Project OSRM, Dennis Luxen, others +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef OSRM_FIXED_POINT_NUMBER_H +#define OSRM_FIXED_POINT_NUMBER_H + +#include +#include + +#include +#include +#include +#include + +namespace osrm +{ + +// implements an binary based fixed point number type +template +class FixedPointNumber +{ + static_assert(FractionalBitSize > 0, "FractionalBitSize must be greater than 0"); + static_assert(FractionalBitSize <= 32, "FractionalBitSize must at most 32"); + + constexpr static const int32_t PRECISION = 1 << FractionalBitSize; + + int32_t m_fixed_point_state; + + // state signage encapsulates whether the state should either represent a + // signed or an unsigned floating point number + using state_signage = + typename std::conditional::type, + decltype(m_fixed_point_state)>::type; + + public: + FixedPointNumber() : m_fixed_point_state(0) {} + + // the type is either initialized with a floating point value or an + // integral state. Anything else will throw at compile-time. + template FixedPointNumber(const T &&input) noexcept + { + static_assert( + std::is_floating_point::value || std::is_integral::value, + "FixedPointNumber needs to be initialized with floating point or integral value"); + m_fixed_point_state = + static_cast(std::round(std::forward(input) * PRECISION)); + } + + // get max value + template ::value>::type * = nullptr> + constexpr static auto max() noexcept -> T + { + return static_cast(std::numeric_limits::max()) / PRECISION; + } + + // get min value + template ::value>::type * = nullptr> + constexpr static auto min() noexcept -> T + { + return static_cast(1) / PRECISION; + } + + // get lowest value + template ::value>::type * = nullptr> + constexpr static auto lowest() noexcept -> T + { + return static_cast(std::numeric_limits::min()) / PRECISION; + } + + // cast to floating point type T, return value + template ::value>::type * = nullptr> + operator T() const noexcept + { + // casts to external type (signed or unsigned) and then to float + return static_cast(static_cast(m_fixed_point_state)) / PRECISION; + } + + // warn about cast to integral type T, its disabled for good reason + template ::value>::type * = nullptr> + operator T() const + { + static_assert(std::is_integral::value, + "casts to integral types have been disabled on purpose"); + } + + // compare, ie. sort fixed-point numbers + void operator<(const FixedPointNumber &other) const noexcept + { + return m_fixed_point_state < other.m_fixed_point_state; + } + + // arithmetic operators + FixedPointNumber operator+(const FixedPointNumber &other) const noexcept + { + FixedPointNumber tmp = *this; + tmp.m_fixed_point_state += other.m_fixed_point_state; + return tmp; + } + + FixedPointNumber &operator+=(const FixedPointNumber &other) noexcept + { + this->m_fixed_point_state += other.m_fixed_point_state; + return *this; + } + + FixedPointNumber operator-(const FixedPointNumber &other) const noexcept + { + FixedPointNumber tmp = *this; + tmp.m_fixed_point_state -= other.m_fixed_point_state; + return tmp; + } + + FixedPointNumber &operator-=(const FixedPointNumber &other) noexcept + { + this->m_fixed_point_state -= other.m_fixed_point_state; + return *this; + } + + FixedPointNumber operator*(const FixedPointNumber &other) const noexcept + { + int64_t temp = this->m_fixed_point_state; + temp *= other.m_fixed_point_state; + + // rounding! + if (!truncate_results) + { + temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1); + } + temp >>= FractionalBitSize; + FixedPointNumber tmp; + tmp.m_fixed_point_state = static_cast(temp); + return tmp; + } + + FixedPointNumber &operator*=(const FixedPointNumber &other) noexcept + { + int64_t temp = this->m_fixed_point_state; + temp *= other.m_fixed_point_state; + + // rounding! + temp = temp + ((temp & 1 << (FractionalBitSize - 1)) << 1); + temp >>= FractionalBitSize; + this->m_fixed_point_state = static_cast(temp); + return *this; + } + + FixedPointNumber operator/(const FixedPointNumber &other) const noexcept + { + int64_t temp = this->m_fixed_point_state; + temp <<= FractionalBitSize; + temp /= static_cast(other.m_fixed_point_state); + FixedPointNumber tmp; + tmp.m_fixed_point_state = static_cast(temp); + return tmp; + } + + FixedPointNumber &operator/=(const FixedPointNumber &other) noexcept + { + int64_t temp = this->m_fixed_point_state; + temp <<= FractionalBitSize; + temp /= static_cast(other.m_fixed_point_state); + FixedPointNumber tmp; + this->m_fixed_point_state = static_cast(temp); + return *this; + } +}; + +static_assert(4 == sizeof(FixedPointNumber<1>), "FP19 has wrong size != 4"); +} +#endif // OSRM_FIXED_POINT_NUMBER_H