Skip to content

Conversation

@copybara-service
Copy link

@copybara-service copybara-service bot commented Oct 31, 2025

Consolidate Ink's linear interpolation implementations

We had multiple different naive floating-point lerp implementations sprinkled throughout our code. In some places, we used a + (b - a) * t, which gives incorrect results if b - a overflows, and can be inexact for t = 1. In other places, we used a * (1 - t) + b * t, which is better, but apparently has monotonicity issues [1] and also gives incorrect results when t is infinite and a or b is zero. Better to have one carefully tested definition and use it everywhere, which is what this CL does.

The good news is that C++20 (which we can finally now use in all our build environments) provides a std::lerp function that handles these edge cases. The bad news is that (at least in some of our build environments), it seems to have a bug (b/457491215) where its behavior does not match the standard! So for now our float Lerp definition in this CL has an extra branch to work around that before deferring to std::lerp.

[1] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0811r3.html

@copybara-service copybara-service bot force-pushed the test_826613841 branch 4 times, most recently from ec37ec2 to f07cce2 Compare November 4, 2025 18:52
@copybara-service copybara-service bot changed the title Use std::lerp instead of hand-coded linear interpolation Consolidate Ink's linear interpolation implementations Nov 4, 2025
@copybara-service copybara-service bot force-pushed the test_826613841 branch 2 times, most recently from e74517e to 4009073 Compare November 4, 2025 19:36
We had multiple different naive floating-point lerp implementations sprinkled throughout our code.  In some places, we used `a + (b - a) * t`, which gives incorrect results if `b - a` overflows, and can be inexact for `t = 1`.  In other places, we used `a * (1 - t) + b * t`, which is better, but apparently has monotonicity issues [1] and also gives incorrect results when `t` is infinite and `a` or `b` is zero.  Better to have one _carefully tested_ definition and use it everywhere, which is what this CL does.

The good news is that C++20 (which we can finally now use in all our build environments) provides a `std::lerp` function that handles these edge cases.  The bad news is that (at least in some of our build environments), it seems to have a bug (b/457491215) where its behavior does not match the standard!  So for now our `float Lerp` definition in this CL has an extra branch to work around that before deferring to `std::lerp`.

[1] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0811r3.html

PiperOrigin-RevId: 826613841
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant