speed up slow modulus
diff --git a/include/delaunator.hpp b/include/delaunator.hpp index 11fb812..057855e 100644 --- a/include/delaunator.hpp +++ b/include/delaunator.hpp
@@ -11,6 +11,15 @@ namespace delaunator { +//@see https://stackoverflow.com/questions/33333363/built-in-mod-vs-custom-mod-function-improve-the-performance-of-modulus-op/33333636#33333636 +inline size_t fast_mod(const size_t i, const size_t c) { + return i >= c ? i % c : i; +}; + +inline size_t fast_mod_3(const size_t i) { + return i % 3; +}; + // Kahan and Babuska summation, Neumaier variant; accumulates less FP error inline double sum(const std::vector<double>& x) { double sum = x[0]; @@ -151,7 +160,7 @@ } // monotonically increases with real angle, but doesn't need expensive trigonometry -inline double pseudo_angle(double dx, double dy) { +inline double pseudo_angle(const double dx, const double dy) { const double p = dx / (std::abs(dx) + std::abs(dy)); return (dy > 0.0 ? 3.0 - p : 1.0 + p) / 4.0; // [0..1) } @@ -189,7 +198,7 @@ std::size_t m_legalize_stack[LEGALIZE_STACK_SIZE]; std::size_t legalize(std::size_t a); - std::size_t hash_key(double x, double y); + std::size_t hash_key(double x, double y) const; std::size_t add_triangle( std::size_t i0, std::size_t i1, @@ -354,7 +363,7 @@ size_t key = hash_key(x, y); for (size_t j = 0; j < m_hash_size; j++) { - start = m_hash[(key + j) % m_hash_size]; + start = m_hash[fast_mod(key + j, m_hash_size)]; if (start != INVALID_INDEX && start != hull_next[start]) break; } @@ -441,10 +450,10 @@ std::size_t ar; std::size_t bl; - size_t i = 0; + unsigned int i = 0; m_legalize_stack[i] = ia; size_t size = 1; - while(i < size) { + while (i < size) { if (i >= LEGALIZE_STACK_SIZE) { throw std::runtime_error("Legalize stack overflow"); @@ -471,12 +480,13 @@ b = halfedges[a]; - a0 = a - a % 3; - b0 = b - b % 3; + //@see https://embeddedgurus.com/stack-overflow/2011/02/efficient-c-tip-13-use-the-modulus-operator-with-caution/ + a0 = 3 * (a / 3); //a - a % 3; + b0 = 3 * (b / 3); //b - b % 3; - al = a0 + (a + 1) % 3; - ar = a0 + (a + 2) % 3; - bl = b0 + (b + 2) % 3; + al = a0 + fast_mod_3(a + 1); + ar = a0 + fast_mod_3(a + 2); + bl = b0 + fast_mod_3(b + 2); const std::size_t p0 = triangles[ar]; const std::size_t pr = triangles[a]; @@ -518,29 +528,29 @@ link(b, halfedges[ar]); link(ar, bl); - std::size_t br = b0 + (b + 1) % 3; + std::size_t br = b0 + fast_mod_3(b + 1); if (i < size) { //move elements down the stack - for(auto mi = size - 1; mi >= i; mi--) { + for (auto mi = size - 1; mi >= i; mi--) { m_legalize_stack[mi + 2] = m_legalize_stack[mi]; } } m_legalize_stack[i] = a; m_legalize_stack[i + 1] = br; - size+=2; + size += 2; } } return ar; } -std::size_t Delaunator::hash_key(double x, double y) { +inline std::size_t Delaunator::hash_key(const double x, const double y) const { const double dx = x - m_center_x; const double dy = y - m_center_y; - return static_cast<std::size_t>(std::llround( - std::floor(pseudo_angle(dx, dy) * static_cast<double>(m_hash_size)))) % - m_hash_size; + return fast_mod( + static_cast<std::size_t>(std::llround(std::floor(pseudo_angle(dx, dy) * static_cast<double>(m_hash_size)))), + m_hash_size); } std::size_t Delaunator::add_triangle(