Skip to content

Add exact results for trig fcns on π #42595

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

Merged
merged 1 commit into from
Oct 23, 2021
Merged

Add exact results for trig fcns on π #42595

merged 1 commit into from
Oct 23, 2021

Conversation

timholy
Copy link
Member

@timholy timholy commented Oct 11, 2021

The argument in favor here is that since Julia has already gone to the
trouble to encode π exactly, and trig functions are defined in terms of
π, they should give exact answers for this particular constant. log(ℯ)
has a similar definition and test that log(ℯ) === 1. I decided here
not to require a specific return type as long as it was numerically
exact. (Arguably, we could also have chosen log(::typeof(ℯ)) = true.)
I chose Int because there is no obvious reason to impose a particular
precision.

Potential concerns: how this will play with autodiff. But the same issue applies to log(ℯ),
and my guess is that it will be a non-issue.

@timholy
Copy link
Member Author

timholy commented Oct 11, 2021

For reference, here's the current behavior:

julia> sin(π)
1.2246467991473532e-16

julia> sincos(π)
(1.2246467991473532e-16, -1.0)

julia> sinpi(1)
0.0

julia> sincospi(1)
(0.0, -1.0)

and here's the new one:

julia> sin(π)
0

julia> sincos(π)
(0, -1)

julia> sinpi(1)
0

julia> sincospi(1)
(0, -1)

@KristofferC
Copy link
Member

KristofferC commented Oct 11, 2021

Ref the discussion in #35820 and #35823.

@timholy
Copy link
Member Author

timholy commented Oct 11, 2021

Given the concerns expressed in #35823 it would not be crazy to make these return Float64 in Julia 1.x. I'm happy to make that change; the numerical precision is frankly more important to me than the return type.

We could mark the Int return type as a TODO for Julia 2.0, or perhaps take the more radical approach and turn these constants into functions, e.g., pi(Float32). That has its own negatives but would end any misperception that these are supposed to emulate their actual mathematical concepts (e.g, now -(-π) == π returns false).

@oscardssmith oscardssmith added the triage This should be discussed on a triage call label Oct 11, 2021
@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Oct 14, 2021

You have your reasons for Base.sin(::Irrational{:π}) = 0 while it only works for π, e.g. not exactly for -π or 2π (with tau as available in a package or two_pi, it could work).

I'm thinking could the float version be changed slightly (its polynomials) to return exact float values, for:

julia> sin(π)
1.2246467991473532e-16

and some few other exact constants, e.g. -π, and possibly only additionally -2π and 2π? As those are very commonly used. I realize that's what sinpi is for, so the counterargument would be it could lead people into false sense of security for integer multiples of π. I'm just thinking is it (easily) possible to put in constraints to calculate to correct polynomials (without sacrificing accuracy for other values), and might it be a replacement for your use case.

@timholy
Copy link
Member Author

timholy commented Oct 14, 2021

There is sinpi for that. The problem with doing something special for particular floating-point values is that unless done extremely cleverly it will introduce a branch and that will hammer performance in some settings (e.g., it will disable @simd).

@oscardssmith
Copy link
Member

The problem is that making sin(Float64(pi)) return 0 is that it is incorrect. Float64(pi) returning 0.0 would mean that it was wrong by 4368955796522032135 ULPs

sinpi(x::Integer) = x >= 0 ? zero(float(x)) : -zero(float(x))
cospi(x::Integer) = isodd(x) ? -one(float(x)) : one(float(x))
sinpi(i::Integer) = 0
cospi(i::Integer) = iseven(i) ? 1 : -1
Copy link
Member

Choose a reason for hiding this comment

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

Triage says 👎 because this is breaking and has been rejected before. But at least it should be in a separate PR if it's going to be considered.

@JeffBezanson
Copy link
Member

Triage thinks we can add the methods for pi, but they should return Float64 for minimal breakage. That can easily be justified, since then it's just a matter of returning a more correct answer. Note cot returns a Float64 here anyway.

@JeffBezanson JeffBezanson removed the triage This should be discussed on a triage call label Oct 21, 2021
@timholy
Copy link
Member Author

timholy commented Oct 22, 2021

That's a good triage outcome (what I expected & like).

Since Julia  has  already gone to the trouble to encode π exactly,
and trig functions are defined in terms of π, they should give exact
answers for this particular constant.
@timholy timholy merged commit 31f67db into master Oct 23, 2021
@timholy timholy deleted the teh/scpi branch October 23, 2021 08:46
LilithHafner pushed a commit to LilithHafner/julia that referenced this pull request Feb 22, 2022
Since Julia has gone to the trouble to encode π exactly,
and trig functions are defined in terms of π, they should give exact
answers for this particular constant.
LilithHafner pushed a commit to LilithHafner/julia that referenced this pull request Mar 8, 2022
Since Julia has gone to the trouble to encode π exactly,
and trig functions are defined in terms of π, they should give exact
answers for this particular constant.
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.

6 participants