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

remove sincosd #60

Closed
wants to merge 1 commit into from
Closed

remove sincosd #60

wants to merge 1 commit into from

Conversation

valarauca
Copy link
Contributor

As a side effect also remove fmod (as now it is deadcode)

  • I agree to follow the project's code of conduct.
  • I added an entry to CHANGES.md if knowledge of this change could be valuable to users.

Two Regressions. One minor & One Major

When solving the direct problem, bad values f64::INFINITE & f64::NAN won't result in the output being 0, only extremely close to 0. Not really worried about this, sort of falls in the case of "garbage in, garbage out".

1/50k of the GeodTest.dat cases fails 😱 (by 6.9e-7 the % error is 3e-12). This (AFAIT) comes down to quadrant normalization. It down is seems that sincosd differs from .to_radians().sin_cos() by ~1e-16 when dealing with values extremely close to +/-180°.

In my local testing
image

It is amusing at the atan2 of the 2 values is correct to within e-16, but just not the sin/cos.

Technically a regression, by nearly the smallest order (I'm not joking, there are only 2 64bit floating point values between the two results). I'll let project management judge if that is deal breaking.

As a side effect also remove fmod (as now it is deadcode)
}

/// Compute sine and cosine of x in degrees
pub fn sincosd(x: f64) -> (f64, f64) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This repository was originally ported from the python version of geographiclib, but is looking more and more like the cpp version over time, especially as we've done performance related work.

Because I'm not as knowledgeable in the domain as the upstream author (Charles Karney), I almost always prefer code that looks like theirs. They've put a lot of thought into robustness and error checking.

With your PR, I see impressive perf improvements (5-10%), but if I leave the original method in tact, and replace only the sin/cos calls with a call to sin_cos, I see no measurable wins at all, which suggests to me all the perf wins we're getting are from deleting the error/robustness checks. I'm not sure that's a good idea.

That said, our existing impl looks pretty far from the cpp version. This repository was originally a port of the python implementation, but has grown to look more like the cpp one as time has gone on. It's possible we could get some perf wins by making our sincosd look more like the cpp version.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking a little deeper, it looks like even the original version already compiles down to sincos in asm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but if I leave the original method in tact, and replace only the sin/cos calls with a call to sin_cos, I see no measurable wins at all, which suggests to me all the perf wins we're getting are from deleting the error/robustness checks. I'm not sure that's a good idea.

This probably has to do with inlined vs not inlined.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess is that it's a specific compiler optimization like this: https://bugs.llvm.org/show_bug.cgi?id=13204

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that minor changes in final values for major operations (like direct or inverse) using infinite or NaN values doesn't feel too concerning, though there's some elegance value in them coming out to exactly 0.

Inputs very close to +/-180° feel more likely to matter, since inputs in that range may be quite common. One of the things I struggled with when I was working on this project was the issue of subtle differences in behavior of Rust vs C++ trig operations. I never solidly pinned down whether the differences were due to one sometimes managing to tease out a little more precision than the other, or whether it's just different noise and both are basically random at the point where they differ. The same sort of question comes up for the very small behavior changes described here. As @michaelkirk says, though, my personal impulse is to stick as close to the Karney implementation as possible, except in cases where it's very clear that we should do otherwise. Unfortunately, I'm unlikely to get enough time to gain any real insight into whether the behavior changes here are positive, negative, or neutral.

Regardless of how @michaelkirk calls it, this PR is certainly an interesting experiment. Thank you for trying it out.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made an alternative PR at #61. The perf gains are smaller, but it passes all the same tests as the original code.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sin/cos calls with a call to sin_cos

Because of sin_cos implementation is just call of sin and cos: https://doc.rust-lang.org/src/std/f64.rs.html#785-787 . The idea is that llvm optimize it in proper way. But sometimes llvm can not do the same, as direct sincos call: llvm/llvm-project#76152

@valarauca
Copy link
Contributor Author

No worries.

@valarauca valarauca closed this Jan 27, 2024
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.

4 participants