Recalculate lerp if we got infinity. Eliminates some overflows.#1918
Conversation
Thank you for finding some issues. I fixed some but I have no idea how to restore monotonicity for lerp :( |
Never mind. It can be tricky to implement floating point functionalities when there are requirements on precision, handling of extreme values, and/or preservation of math properties.
|
|
FWIW, this could be fixed with a fused multiply-add --const auto _Candidate = _ArgA + _ArgT * (_ArgB - _ArgA);
++const auto _Candidate = std::fma(_ArgT, _ArgB - _ArgA, _ArgA);But |
|
Well, at least we can reuse new test code :( What do you think about fma? It seems it doesn't overflow but we can get different results for runtime/compiletime invocation of lerp... https://gcc.godbolt.org/z/T564z58qo |
|
The condition we have to handle here is limited to | auto _Smaller = _ArgT;
auto _Larger = _ArgB - _ArgA;
auto _Abs_smaller = _Float_abs(_Smaller);
auto _Abs_larger = _Float_abs(_Larger);
if (_Abs_larger < _Abs_smaller) {
_STD swap(_Smaller, _Larger);
_STD swap(_Abs_smaller, _Abs_larger);
}
if (_Abs_larger > _STD sqrt(numeric_limits<_Ty>::max()) && _Abs_smaller > 1) {
return 2 * (_Ty{0.5} * _ArgA + _Smaller * (_Ty{0.5} * _Larger));
} else {
return _ArgA + _Smaller * _Larger;
}
|
|
Note that we have |b - a| <= // precondition: T{0.5} * t is exact
T linear_for_lerp(T intercept, T slope, T t) {
T half_prod = slope * (T{0.5} * t);
if (abs(half_prod) <= numeric_limits<T>::max() * T{0.5}) {
return intercept + slope * t;
} else {
return T{2} * (T{0.5} * intercept + half_prod);
}
}
T lerp(T a, T b, T t) {
// [...]
{
if (abs(t) < T{1}) {
T candidate = a + t * (b - a);
// [...] fix monotonicity
}
if (t >= T{1}) {
return linear_for_lerp(b, b - a, t - T{1});
}
// t <= -1
return linear_for_lerp(a, b - a, t);
}
// [[...]]
} |
Co-authored-by: Michael Schellenberger Costa <[email protected]>
Co-authored-by: Adam Bucior <[email protected]>
Co-authored-by: statementreply <[email protected]>
Co-authored-by: Curtis J Bezault <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]> Co-authored-by: Matt Stephanson <[email protected]>
|
I'm speculatively mirroring this to the MSVC-internal repo. Further changes can be pushed, but please notify me. |
|
|
||
| return _STD fma(_ArgT, _ArgB - _ArgA, _ArgA); | ||
| } | ||
|
|
There was a problem hiding this comment.
We need to find that Twitter thread mocking our huge implementation of lerp to let them know we've added another 25 lines. (No change requested.)
|
Thanks for infinitely improving this implementation! ♾️ 🚀 😹 |
…osoft#1918) Co-authored-by: Adam Bucior <[email protected]> Co-authored-by: Alexander Bolz <[email protected]> Co-authored-by: Curtis J Bezault <[email protected]> Co-authored-by: Matt Stephanson <[email protected]> Co-authored-by: Michael Schellenberger Costa <[email protected]> Co-authored-by: statementreply <[email protected]> Co-authored-by: Stephan T. Lavavej <[email protected]>
Fixes #1917