Recently I was watching two YouTube videos criticizing a function which sums the even elements in an inclusive range, the original function looks like this:
int calculate(int bottom, int top) { if (top > bottom) { int sum = 0; for (int number = bottom; number <= top; number++) { if (number % 2 == 0) { sum += number; } } return sum; } else { return 0; } }
original source video
While I agree the original function could be formatted better with less indentation and early returns, it seems the solutions proposed in C++, Rust & Haskell are making heavy use of their variations of .filter
& .reduce
like functional programming which seems like a lot of overhead for something like this...
Which led to me spending a bit too much time writing the following functions, with the intent to make the function blazingly fast, more concise and removing all layers of nesting (as intended by the source video).
The Math Approach
I remember learning a math formula for summing numbers in a sequence which I looked up for quick refresher, and found an even better solution for summing only even numbers:
n • (n + 1)
Where n
is the number of numbers in the range. My initial attempts at just subtracting the total sum of evens from the top and bottom failed (more on this later), which led me to trying a different formula:
and after a bit more time than I like to admit, I arrived at the following solution:
int sumOnlyEvenNumbersInRange(int bottom, int top) {
int x = bottom + (bottom & 1); // next even if odd
int y = top + (top & 1); // previous even if odd
return (y - x + 2) * 0.25 * ((x ^ y) + ((x & y) << 1));
}
Which I'll admit looks a lot worse than it really is, but was the product of me combing the math terms and then substituting bitwise operators where applicable. The issue I realized I encountered earlier is that when bottom
is odd we need to start the sequence at the next even and likewise if top
is odd we need to end at the previous even number. After discovering this I revisited my first attempt, and finally got the following to work:
int sumOnlyEvenNumbersInRange(int bottom, int top) {
int x = (bottom + (bottom & 1)) >> 1;
int y = (top - (top & 1)) >> 1;
return y * (y + 1) - x * (x - 1);
}
Which to be honest I'm pretty happy about, even though I still dream of an inline function. Anyways, I would be pretty upset if I saw this in a code-review the way it is and I realize it still doesn't account for when top
< bottom
, so here is the finalized version:
int sumOnlyEvenNumbersInRange(int bottom, int top) {
if (bottom > top) return 0; // edge case
int x = (bottom + (bottom & 1)) >> 1; // first even number in range divided by 2
int y = (top - (top & 1)) >> 1; // last even number in range divided by 2
return y * (y + 1) - x * (x - 1); // difference of evens between x and y
}
I know it isn't the most readable code, but that wasn't really the goal here. This won't be used in production and is just for fun, so I'm pretty happy with it, but it would be awesome if there was a way to
- Handle the first / last even in range more elegantly.
- Inline the entire function.
((x ^ y) + ((x & y) << 1))
is equivalent to(x + y)
by definition (recursive definition of addition). \$\endgroup\$