Prior art: C++20 std::midpoint
from P0811r3.
I think std::lerp
is over-specified to the point where it's not useful for it's intended purpose (games/gfx) since handling edge cases is too expensive, but I do think that std::midpoint
's specification describes the problem well and is generally what you want from a midpoint/mean/average.
There might be a way to do it branchless, but P0811r3 provides the example implementation of (roughly translated into pseudo Rust by me)
const fn midpoint<Int>(a: Int, b: Int) -> Int {
if a > b {
a.wrapping_add(a.wrapping_sub(b)/2)
} else {
a.wrapping_sub(b.wrapping_sub(a)/2)
}
}
const fn midpoint<Float>(a: Float, b: Float) -> Float {
if a.is_normal() && b.is_normal() {
a/2 + b/2
} else {
(a+b)/2
}
}
Do note that a+(b-a)/2
works no matter the sign so long as there isn't overflow. The trivial (a+b)/2
truncates towards 0; I'm not exactly sure the rounding behavior of this integer implementation is, but P0811r3 claims it's what you'd typically want from an e.g. binary search midpoint.