Skip to content
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

lerp()'s implementation has a loss of precision when inputs span multiple orders of magnitude #275

Open
james7132 opened this issue Mar 4, 2022 · 3 comments

Comments

@james7132
Copy link
Contributor

The general implementation of lerp in glam for floating point types takes the form as follows:

fn lerp(a: Self, b: Self, t: f32) -> Self {
  a + (b - a) * t
}

However, this presents floating point precision issues if a and b have very different exponent values due to the (b - a) in the computation. You can test this via lerp(-16.0e30, 16.0, 1.0) returning 0.0 instead of the correct 16.0. It may be more accurate to use the following form:

fn lerp(a: Self, b: Self, t: f32) -> Self {
  a * (1.0 - t) + b * t
}

This may not be a significant regression in performance as floating point multiplication is generally much faster than addition.

@bitshifter
Copy link
Owner

Sorry, I've been meaning to get to this. I've been mulling over if changing the default implementation would cause anyone issues. Allegedly the main advantage of the method glam is using is it is monotonic, whereas apparently the precise version is not, see https://en.wikipedia.org/wiki/Linear_interpolation#Programming_language_support.

I think if I am to merge your PR I will bump the glam version number so people don't get a surprise change in behaviour.

The other option I guess would be to add a second "precise" lerp method, I think I'd rather not do that though.

@bitshifter
Copy link
Owner

Another thing to consider with changing the current implementation is currently t is not clamped, but it will extrapolate just fine if t < 0 or t > 1. If users happen to be relying on this behaviour then changing the implementation will break their code.

Perhaps it would be better to offer a separate lerp_precise method for those that need it. This is the approach that vek has taken (see comparison of different lib's approaches rust-lang/rust#86269 (comment)).

@vallentin
Copy link

I just noticed that glam uses the "imprecise" linear interpolation formula, and then found this issue.

Another thing to consider with changing the current implementation is currently t is not clamped, but it will extrapolate just fine if t < 0 or t > 1. If users happen to be relying on this behaviour then changing the implementation will break their code.

Can you elaborate on what you imply with this? Since the "precise" implementation will also extrapolate outside the range of 0 and 1

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 a pull request may close this issue.

3 participants