Mercurial > mm7
diff Math.h @ 1131:71ba92960bc5
banker's rounding template made as fast as before and a bit more safe
author | Grumpy7 |
---|---|
date | Sat, 01 Jun 2013 13:52:00 +0200 |
parents | d98415be04ca |
children | 0d6c7ff3cddd |
line wrap: on
line diff
--- a/Math.h Fri May 31 23:38:43 2013 +0200 +++ b/Math.h Sat Jun 01 13:52:00 2013 +0200 @@ -1,5 +1,7 @@ #pragma once - +#include <cassert> +#include <limits> +#include <float.h> /* 186 */ @@ -37,76 +39,44 @@ #include <cstdlib> #include <ciso646> -namespace rounding -{ - - //-------------------------------------------------------------------------- - // round down - // Bias: -Infinity - using std::floor; - - //-------------------------------------------------------------------------- - // round up - // Bias: +Infinity - using std::ceil; +template <typename FloatType> +int bankersRounding( + const FloatType& value + ) { + assert("Method unsupported for this type" && false); + return value; +} - //-------------------------------------------------------------------------- - // symmetric round up - // Bias: away from zero - template <typename FloatType> - FloatType ceil0( const FloatType& value ) +template<> static int bankersRounding<float>(const float& inValue) +{ + union Cast { - FloatType result = std::ceil( std::fabs( value ) ); - return (value < 0.0) ? -result : result; - } - - //-------------------------------------------------------------------------- - // Common rounding: round half up - // Bias: +Infinity - template <typename FloatType> - FloatType roundhalfup( const FloatType& value ) - { - return std::floor( value +0.5 ); - } + double d; + long l; + }; + volatile Cast c; + c.d = inValue + 6755399441055744.0; + return c.l; +} - //-------------------------------------------------------------------------- - // symmetric round half up - // Bias: away from zero - template <typename FloatType> - FloatType roundhalfup0( const FloatType& value ) - { - FloatType result = roundhalfup( std::fabs( value ) ); - return (value < 0.0) ? -result : result; - } - - //-------------------------------------------------------------------------- - // round half even (banker's rounding) - // Bias: none - template <typename FloatType> - FloatType bankersRounding( - const FloatType& value, - const FloatType& epsilon = ROUNDING_EPSILON - ) { - if (value < 0.0) return -bankersRounding <FloatType> ( -value, epsilon ); +#pragma push_macro("max") +#undef max - FloatType ipart; - std::modf( value, &ipart ); - - // If 'value' is exctly halfway between two integers - if (abs((value -(ipart +0.5))) < epsilon) - { - // If 'ipart' is even then return 'ipart' - if (std::fmod( ipart, 2.0 ) < epsilon) - return ipart; +template<> static int bankersRounding<double>(const double& inValue) +{ + double maxValue = std::numeric_limits<int>::max(); + assert(maxValue - 6755399441055744.0 >= inValue); + union Cast + { + double d; + long l; + }; + volatile Cast c; + c.d = inValue + 6755399441055744.0; + return c.l; +} - // Else return the nearest even integer - return ceil0( ipart +0.5 ); - } - // Otherwise use the usual round to closest - // (Either symmetric half-up or half-down will do0 - return roundhalfup0( value ); - } +#pragma pop_macro("max") -} extern struct stru193_math *stru_5C6E00; \ No newline at end of file