-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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... |
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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