From 3498e9214fabc20ad1bec9c1841a2be801c209d6 Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Tue, 7 May 2013 13:40:18 +0900 Subject: [PATCH] fix fmod --- sprout/math/fmod.hpp | 57 +++++++++++++++++++++++++++++++++++---- sprout/math/quotient.hpp | 24 ++++++++++++----- sprout/math/rem_quo.hpp | 36 +++++++++++++++++++------ sprout/math/remainder.hpp | 29 +++++++++++++++++--- 4 files changed, 123 insertions(+), 23 deletions(-) diff --git a/sprout/math/fmod.hpp b/sprout/math/fmod.hpp index b5cc0842..20df9e84 100644 --- a/sprout/math/fmod.hpp +++ b/sprout/math/fmod.hpp @@ -3,23 +3,66 @@ #include #include -#include #include #include #include #include #include -#include +#include +#include +#include #include #include namespace sprout { namespace math { namespace detail { + template + inline SPROUT_CONSTEXPR T + fmod_impl_6(T x, T y, T x1) { + return x1 >= y + ? x < 0 ? -(x1 - y) : x1 - y + : x < 0 ? -x1 : x1 + ; + } + template + inline SPROUT_CONSTEXPR T + fmod_impl_5(T x, T y, T x1, T y1, T z, int iscy, int idiff, int i) { + return i != idiff + ? z >= 0 + ? sprout::math::detail::fmod_impl_5(x, y, z + z, y1, z + z - y1, iscy, idiff, i + 1) + : sprout::math::detail::fmod_impl_5(x, y, x1 + x1, y1, x1 + x1 - y1, iscy, idiff, i + 1) + : sprout::math::detail::fmod_impl_6(x, y, sprout::math::scalbn(x1, iscy)) + ; + } + template + inline SPROUT_CONSTEXPR T + fmod_impl_4(T x, T y, T x1, T y1, int iscy, int idiff, int i) { + return sprout::math::detail::fmod_impl_5(x, y, x1, y1, x1 - y1, iscy, idiff, i); + } + template + inline SPROUT_CONSTEXPR T + fmod_impl_3(T x, T y, T x1, int iscx, int iscy, int idiff) { + return idiff ? sprout::math::detail::fmod_impl_4(x, y, sprout::math::scalbn(x1, -iscx), sprout::math::scalbn(y, -iscy), iscy, idiff, 0) + : sprout::math::detail::fmod_impl_6(x, y, x1) + ; + } + template + inline SPROUT_CONSTEXPR T + fmod_impl_2(T x, T y, T x1, int iscx, int iscy) { + return sprout::math::detail::fmod_impl_3(x, y, x1, iscx, iscy, iscx - iscy); + } + template + inline SPROUT_CONSTEXPR T + fmod_impl_1(T x, T y, T x1) { + return y > x1 ? x + : sprout::math::detail::fmod_impl_2(x, y, x1, sprout::math::ilogb(x1), sprout::math::ilogb(y)) + ; + } template inline SPROUT_CONSTEXPR T fmod_impl(T x, T y) { - return x - sprout::math::trunc(x / y) * y; + return sprout::math::detail::fmod_impl_1(x, sprout::math::fabs(y), sprout::math::fabs(x)); } template< @@ -34,9 +77,9 @@ namespace sprout { : std::numeric_limits::quiet_NaN() : y : sprout::math::isnan(x) ? x + : x == 0 && y != 0 ? x : x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 ? -std::numeric_limits::quiet_NaN() - : x == 0 ? x : y == std::numeric_limits::infinity() || y == -std::numeric_limits::infinity() ? x : static_cast(sprout::math::detail::fmod_impl( static_cast::type>(x), @@ -58,7 +101,11 @@ namespace sprout { return sprout::math::detail::fmod(static_cast(x), static_cast(y)); } } // namespace detail - + // + // issue: + // fmod(-NaN, -NaN) returns -NaN . + // # returns +NaN . ( same as fmod(+NaN, +NaN) ) + // using sprout::math::detail::fmod; } // namespace math diff --git a/sprout/math/quotient.hpp b/sprout/math/quotient.hpp index 8fb8db54..39cb3262 100644 --- a/sprout/math/quotient.hpp +++ b/sprout/math/quotient.hpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -13,6 +16,12 @@ namespace sprout { namespace math { namespace detail { + template + inline SPROUT_CONSTEXPR T + quotient_impl(T x, T y) { + return sprout::math::iround(x / y); + } + template< typename R = int, typename FloatType, @@ -20,14 +29,17 @@ namespace sprout { > inline SPROUT_CONSTEXPR R quotient(FloatType x, FloatType y) { - return x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 - ? std::numeric_limits::quiet_NaN() - : x == 0 ? FloatType(0) - : y == std::numeric_limits::infinity() || y == -std::numeric_limits::infinity() ? FloatType(0) - : sprout::math::iround(x / y) + return sprout::math::isnan(y) || sprout::math::isnan(x) ? R(0) + : x == 0 && y != 0 ? R(0) + : x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 + ? R(0) + : y == std::numeric_limits::infinity() || y == -std::numeric_limits::infinity() ? R(0) + : static_cast(sprout::math::detail::quotient_impl( + static_cast::type>(x), + static_cast::type>(y) + )) ; } - template< typename R = int, typename ArithmeticType1, diff --git a/sprout/math/rem_quo.hpp b/sprout/math/rem_quo.hpp index 0fee35de..c3737a44 100644 --- a/sprout/math/rem_quo.hpp +++ b/sprout/math/rem_quo.hpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -14,17 +17,20 @@ namespace sprout { namespace math { namespace detail { + template + inline SPROUT_CONSTEXPR sprout::pair + rem_quo_ret(Pair const& p) { + typedef sprout::pair type; + return type(static_cast(p.first), p.second); + } + template inline SPROUT_CONSTEXPR sprout::pair rem_quo_impl(T x, T y, R quo) { typedef sprout::pair type; - return x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 - ? type(std::numeric_limits::quiet_NaN(), quo) - : x == 0 ? type(T(0), quo) - : y == std::numeric_limits::infinity() || y == -std::numeric_limits::infinity() ? type(x, quo) - : type(x - quo * y, quo) - ; + return type(x - quo * y, quo); } + template< typename R = int, typename FloatType, @@ -32,9 +38,23 @@ namespace sprout { > inline SPROUT_CONSTEXPR sprout::pair rem_quo(FloatType x, FloatType y) { - return sprout::math::detail::rem_quo_impl(x, y, sprout::quotient(x, y)); + typedef sprout::pair type; + return sprout::math::isnan(y) + ? sprout::math::isnan(x) + ? sprout::math::signbit(y) || sprout::math::signbit(x) ? type(-std::numeric_limits::quiet_NaN(), R(0)) + : type(std::numeric_limits::quiet_NaN(), R(0)) + : type(y, R(0)) + : x == 0 && y != 0 ? type(FloatType(0), R(0)) + : x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 + ? type(std::numeric_limits::quiet_NaN(), R(0)) + : y == std::numeric_limits::infinity() || y == -std::numeric_limits::infinity() ? type(x, R(0)) + : sprout::math::detail::rem_quo_ret(sprout::math::detail::rem_quo_impl( + static_cast::type>(x), + static_cast::type>(y), + sprout::math::quotient(x, y) + )) + ; } - template< typename R = int, typename ArithmeticType1, diff --git a/sprout/math/remainder.hpp b/sprout/math/remainder.hpp index af4fd035..eca81b88 100644 --- a/sprout/math/remainder.hpp +++ b/sprout/math/remainder.hpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -13,20 +16,38 @@ namespace sprout { namespace math { namespace detail { + template + inline SPROUT_CONSTEXPR T + remainder_impl(T x, T y) { + return x - sprout::math::round(x / y) * y; + } + template< typename FloatType, typename sprout::enabler_if::value>::type = sprout::enabler > inline SPROUT_CONSTEXPR FloatType remainder(FloatType x, FloatType y) { - return x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 + return sprout::math::isnan(y) + ? sprout::math::isnan(x) + ? sprout::math::signbit(y) || sprout::math::signbit(x) ? -std::numeric_limits::quiet_NaN() + : std::numeric_limits::quiet_NaN() + : y + : sprout::math::isnan(x) ? x + : x == 0 && y != 0 ? x + : x == std::numeric_limits::infinity() || x == -std::numeric_limits::infinity() || y == 0 ? std::numeric_limits::quiet_NaN() - : x == 0 ? FloatType(0) : y == std::numeric_limits::infinity() || y == -std::numeric_limits::infinity() ? x - : x - sprout::math::round(x / y) * y +#if SPROUT_USE_BUILTIN_CMATH_FUNCTION + : std::remainder(x, y) +#else + : static_cast(sprout::math::detail::remainder_impl( + static_cast::type>(x), + static_cast::type>(y) + )) +#endif ; } - template< typename ArithmeticType1, typename ArithmeticType2,