Skip to content

Commit 01cfb3e

Browse files
committed
speed up slow modulus
1 parent 36df20a commit 01cfb3e

File tree

1 file changed

+27
-17
lines changed

1 file changed

+27
-17
lines changed

include/delaunator.hpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@
1111

1212
namespace delaunator {
1313

14+
//@see https://stackoverflow.com/questions/33333363/built-in-mod-vs-custom-mod-function-improve-the-performance-of-modulus-op/33333636#33333636
15+
inline size_t fast_mod(const size_t i, const size_t c) {
16+
return i >= c ? i % c : i;
17+
};
18+
19+
inline size_t fast_mod_3(const size_t i) {
20+
return i % 3;
21+
};
22+
1423
// Kahan and Babuska summation, Neumaier variant; accumulates less FP error
1524
inline double sum(const std::vector<double>& x) {
1625
double sum = x[0];
@@ -151,7 +160,7 @@ inline bool check_pts_equal(double x1, double y1, double x2, double y2) {
151160
}
152161

153162
// monotonically increases with real angle, but doesn't need expensive trigonometry
154-
inline double pseudo_angle(double dx, double dy) {
163+
inline double pseudo_angle(const double dx, const double dy) {
155164
const double p = dx / (std::abs(dx) + std::abs(dy));
156165
return (dy > 0.0 ? 3.0 - p : 1.0 + p) / 4.0; // [0..1)
157166
}
@@ -189,7 +198,7 @@ class Delaunator {
189198
std::size_t m_legalize_stack[LEGALIZE_STACK_SIZE];
190199

191200
std::size_t legalize(std::size_t a);
192-
std::size_t hash_key(double x, double y);
201+
std::size_t hash_key(double x, double y) const;
193202
std::size_t add_triangle(
194203
std::size_t i0,
195204
std::size_t i1,
@@ -354,7 +363,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
354363

355364
size_t key = hash_key(x, y);
356365
for (size_t j = 0; j < m_hash_size; j++) {
357-
start = m_hash[(key + j) % m_hash_size];
366+
start = m_hash[fast_mod(key + j, m_hash_size)];
358367
if (start != INVALID_INDEX && start != hull_next[start]) break;
359368
}
360369

@@ -441,10 +450,10 @@ std::size_t Delaunator::legalize(std::size_t ia) {
441450
std::size_t ar;
442451
std::size_t bl;
443452

444-
size_t i = 0;
453+
unsigned int i = 0;
445454
m_legalize_stack[i] = ia;
446455
size_t size = 1;
447-
while(i < size) {
456+
while (i < size) {
448457

449458
if (i >= LEGALIZE_STACK_SIZE) {
450459
throw std::runtime_error("Legalize stack overflow");
@@ -471,12 +480,13 @@ std::size_t Delaunator::legalize(std::size_t ia) {
471480

472481
b = halfedges[a];
473482

474-
a0 = a - a % 3;
475-
b0 = b - b % 3;
483+
//@see https://embeddedgurus.com/stack-overflow/2011/02/efficient-c-tip-13-use-the-modulus-operator-with-caution/
484+
a0 = 3 * (a / 3); //a - a % 3;
485+
b0 = 3 * (b / 3); //b - b % 3;
476486

477-
al = a0 + (a + 1) % 3;
478-
ar = a0 + (a + 2) % 3;
479-
bl = b0 + (b + 2) % 3;
487+
al = a0 + fast_mod_3(a + 1);
488+
ar = a0 + fast_mod_3(a + 2);
489+
bl = b0 + fast_mod_3(b + 2);
480490

481491
const std::size_t p0 = triangles[ar];
482492
const std::size_t pr = triangles[a];
@@ -518,29 +528,29 @@ std::size_t Delaunator::legalize(std::size_t ia) {
518528
link(b, halfedges[ar]);
519529
link(ar, bl);
520530

521-
std::size_t br = b0 + (b + 1) % 3;
531+
std::size_t br = b0 + fast_mod_3(b + 1);
522532

523533
if (i < size) {
524534
//move elements down the stack
525-
for(auto mi = size - 1; mi >= i; mi--) {
535+
for (auto mi = size - 1; mi >= i; mi--) {
526536
m_legalize_stack[mi + 2] = m_legalize_stack[mi];
527537
}
528538
}
529539

530540
m_legalize_stack[i] = a;
531541
m_legalize_stack[i + 1] = br;
532-
size+=2;
542+
size += 2;
533543
}
534544
}
535545
return ar;
536546
}
537547

538-
std::size_t Delaunator::hash_key(double x, double y) {
548+
inline std::size_t Delaunator::hash_key(const double x, const double y) const {
539549
const double dx = x - m_center_x;
540550
const double dy = y - m_center_y;
541-
return static_cast<std::size_t>(std::llround(
542-
std::floor(pseudo_angle(dx, dy) * static_cast<double>(m_hash_size)))) %
543-
m_hash_size;
551+
return fast_mod(
552+
static_cast<std::size_t>(std::llround(std::floor(pseudo_angle(dx, dy) * static_cast<double>(m_hash_size)))),
553+
m_hash_size);
544554
}
545555

546556
std::size_t Delaunator::add_triangle(

0 commit comments

Comments
 (0)