diff options
Diffstat (limited to 'src/third_party/s2/util/math/mathutil.h')
| -rwxr-xr-x | src/third_party/s2/util/math/mathutil.h | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/src/third_party/s2/util/math/mathutil.h b/src/third_party/s2/util/math/mathutil.h index 74ac26c5838..bf607475b64 100755 --- a/src/third_party/s2/util/math/mathutil.h +++ b/src/third_party/s2/util/math/mathutil.h @@ -317,6 +317,33 @@ class MathUtil { vector<bool>* shards_to_read); // -------------------------------------------------------------------- + // Round, IntRound + // These functions round a floating-point number to an integer. They + // work for positive or negative numbers. + // + // Values that are halfway between two integers may be rounded up or + // down, for example IntRound(0.5) == 0 and IntRound(1.5) == 2. This + // allows these functions to be implemented efficiently on Intel + // processors (see the template specializations at the bottom of this + // file). You should not use these functions if you care about which + // way such half-integers are rounded. + // + // Example usage: + // double y, z; + // int x = IntRound(y + 3.7); + // int64 b = Round<int64>(0.3 * z); + // + // Note that the floating-point template parameter is typically inferred + // from the argument type, i.e. there is no need to specify it explicitly. + // -------------------------------------------------------------------- + template <class IntOut, class FloatIn> + static IntOut Round(FloatIn x); + + // Example usage: IntRound(3.6) (no need for IntRound<double>(3.6)). + template <class FloatIn> + static int IntRound(FloatIn x) { return Round<int>(x); } + + // -------------------------------------------------------------------- // FastIntRound, FastInt64Round // Fast routines for converting floating-point numbers to integers. // @@ -329,10 +356,11 @@ class MathUtil { // floating-point pipeline (unless programs are compiled specifically // for the Pentium 4, which has a new instruction to avoid this). // - // Numbers that are halfway between two integers follow the deafult + // Numbers that are halfway between two integers may be rounded up or + // down. This is because the conversion is done using the default // rounding mode, which rounds towards the closest even number in case // of ties. So for example, FastIntRound(0.5) == 0, but - // FastIntRound(1.5) == 2. These functions should only be used with + // FastIntRound(1.5) == 2. These functions should only be used with // applications that don't care about which way such half-integers are // rounded. // @@ -340,8 +368,10 @@ class MathUtil { // functions (for "int" and "int64" only), but it's safer to call them // directly. // - // This functions are equivalent to rint() and llrint(). - // -------------------------------------------------------------------- + // This functions are equivalent to lrint() and llrint() as defined in + // the ISO C99 standard. Unfortunately this standard does not seem to + // widely adopted yet and these functions are not available by default. + // -------------------------------------------------------------------- static int32 FastIntRound(double x) { // This function is not templatized because gcc doesn't seem to be able @@ -369,7 +399,7 @@ class MathUtil { return result; #endif // if defined __x86_64__ || ... #else - return static_cast<int32>(rint(x)); + return Round<int32, double>(x); #endif // if defined __GNUC__ && ... } @@ -395,7 +425,7 @@ class MathUtil { return result; #endif // if defined __i386__ #else - return static_cast<int64>(llrint(x)); + return Round<int64, double>(x); #endif // if defined __GNUC__ && ... } @@ -656,6 +686,35 @@ class MathUtil { } }; +// ========================================================================= // + +#if (defined __i386__ || defined __x86_64__) && defined __GNUC__ + +// We define template specializations of Round() to get the more efficient +// Intel versions when possible. Note that gcc does not currently support +// partial specialization of templatized functions. +template<> +inline int32 MathUtil::Round<int32, double>(double x) { + return FastIntRound(x); +} + +template<> +inline int32 MathUtil::Round<int32, float>(float x) { + return FastIntRound(x); +} + +template<> +inline int64 MathUtil::Round<int64, double>(double x) { + return FastInt64Round(x); +} + +template<> +inline int64 MathUtil::Round<int64, float>(float x) { + return FastInt64Round(x); +} + +#endif + template<typename T> bool MathUtil::WithinFraction(const T x, const T y, const T fraction) { // not just "0 <= fraction" to fool the compiler for unsigned types |
