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