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

Implement tau==2pi (in type-stable manner) #28

Closed
wants to merge 8 commits into from
Closed

Conversation

waldyrious
Copy link
Collaborator

Not sure why I was focused on overriding * all this time. Writing the tau-2pi-equality.md document helped me get a better grasp of the problem, and I realized that adding custom methods for == not only makes more sense, but is also simpler -- and type-stable :)

@giordano
Copy link
Member

I don't think I like this. This should be implemented in julia core for all irrational numbers if there is consensus on such change, I don't see why tau should be special in this regard :)

@waldyrious
Copy link
Collaborator Author

I'd have no problems making a proposal to Base, but what exactly would you suggest the change to be? Here we're allowing two Irrationals to have an exact proportionality relationship with each other (because their mathematical definition pretty much hinges on that relationship), while remaining unequal to everything else, as defined in base. Unless I'm mistaken, none of the other Irrationals in Base do have this sort of relationship with each other.

@codecov
Copy link

codecov bot commented Jun 22, 2017

Codecov Report

Merging #28 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master    #28   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files           2      2           
  Lines          61     67    +6     
=====================================
+ Hits           61     67    +6
Impacted Files Coverage Δ
src/Tau.jl 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update be5d27f...ddeb839. Read the comment docs.

@waldyrious
Copy link
Collaborator Author

Note: while I was at it, I took the opportunity to reorganize the test script and start using the @testset macro. I hadn't realized how many combinations there were in the sintau/costau tests in total -- almost 10,000! I think we might be ok dropping that number a bit by using larger steps and smaller ranges for the approximate output tests, which are the biggest culprits.

@giordano
Copy link
Member

I would split the reorganization of tests from this PR, that change is unrelated and unquestionable

@waldyrious
Copy link
Collaborator Author

Good point. I've rebuilt the testset reorganization changes independently, in #29. I'll rebase this branch over it so that it contains only the equality changes.

@giordano
Copy link
Member

I'd have no problems making a proposal to Base, but what exactly would you suggest the change to be?

A possibility could be

==(x::Irrational, y::T) where {T<:AbstractFloat} = T(x) == y
==(x::T, y::Irrational) where {T<:AbstractFloat} = x == T(y)

In this way:

julia> pi == 3.1415927f0
true

julia> 3.141592653589793 == pi
true

julia> 3.141592653589794 == pi
false

julia> pi == big"3.141592653589793238462643383279502884197169399375105820974944592307816406286198"
true

But speaking for myself I find the argument "an Irrational can't be equal to any decimal number with finite representation" pretty compelling.

@waldyrious
Copy link
Collaborator Author

I see, so every irrational would be equal to (various representations of) itself. I will collect some information from previous discussions, and submit a PR later.

In the meantime, I've rebased this PR to cleanup the changes after the merging of #29. I suppose this change (making 2pi equal to tau) can be handled separately to making every irrational equal to itself, since with this change the original inequality definition remains in place for any other combination.

The exception for tau==2pi is IMO justifiable, given that this is precisely how these two constants are defined -- them not being equal is more likely to cause confusion than the fact that an irrational number is considered equal to what is technically a finite representation. The latter only trips the user if they're analyzing the underlying representation of their code from the point of view of how the computer handles it, rather than whatever conceptual algorithm they're implementing. Even then, that surprise is not likely to cause practical issues, since this change has no performance implications (that I'm aware of).

@giordano
Copy link
Member

The exception for tau==2pi is IMO justifiable, given that this is precisely how these two constants are defined

So you're saying that pi is more fundamental than tau? I thought that in this package was the other way around ;-)

@waldyrious
Copy link
Collaborator Author

waldyrious commented Jun 22, 2017

You know what I mean :P

(edit: just for the sake of completeness: tau = circumference/radius and pi = circumference/diameter and diameter = 2*radius, therefore tau = 2*pipi = tau/2)

@mschauer
Copy link
Member

As you write in the document, in julia 2π is rational because of rounding. So 2π!=tau, in the same way as

julia> π^2/π != π
true

I would not do an ad hoc fix to this by redefining equality.

@waldyrious
Copy link
Collaborator Author

waldyrious commented Jun 27, 2017

Thanks for your input, @mschauer :)

in julia 2π is rational because of rounding

Yes, and this is a technical implementation artifact, not a deliberate choice. The current inequality is actually based on mixing two extremes of the abstraction spectrum: one based on the low-level technical limitations of floating point number representation, and another based on the high-level mathematical properties of irrational numbers. I'm not entirely convinced that combining these two concepts, from very distinct (almost opposite) abstraction levels, as premises for reaching the conclusion of inequality (and going out of our way to manually define such inequality, which otherwise the promotion mechanism would handle as one would intuitively expect) is a sound choice.

I would not do an ad hoc fix to this by redefining equality.

That was exactly what was done in JuliaLang/julia#9198, though: defining an override to the equality method (and a hardcoded one at that!), so that it returned the the result it should. according to the author of that change. The solution presented here has exactly the same kind of rationale (ensuring the result of tau==2pi is what it should be, per the mathematical definition), and exactly the same kind of implementation. I don't see why it's objectionable on those grounds in particular.

One objection I'm willing to concede to is that perhaps a more perfect way to do this could be found -- but until an implementation plan is defined, and considering that this change maintains type stability and has no performance impact (nor it affects the strict inequality for all other Irrational comparisons), I'm inclined to go ahead and merge in honor of Tau day tomorrow. We can always replace this implementation with something better down the road, and I'm very much open to that.

@mschauer
Copy link
Member

After your change either

julia> x <= y < z <= x
true

with x, y, z = τ, 2π, (2*big(π)+ big(2π))/2
(or

julia> tau == 2pi
true

julia> tau <= 2pi
false

if you do not recompile <=)

src/Tau.jl Outdated
import Base.==
=={T<:Real}(::Irrational{:τ}, n::T) = n == 2*T(π)
=={T<:Real}(n::T, ::Irrational{:τ}) = n == 2*T(π)
=={T<:Real}(::Irrational{:π}, n::T) = n == T(τ)/2
Copy link
Member

@giordano giordano Jun 28, 2017

Choose a reason for hiding this comment

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

Lines 20, 21, and 29 are acts of type-piracy of Base's types.

@giordano
Copy link
Member

Yes, and this is a technical implementation artifact, not a deliberate choice.

This isn't actually true, it is a deliberate choice not making arithmetic operations for Irrationals, see JuliaLang/julia#21535 (comment)

Taking the risk of repeating myself, I'm against such change, it should be either done in Base or not done at all here. tau is a cool and useful constant, but not more special than others in Base, it shouldn't be treated differently.

@waldyrious
Copy link
Collaborator Author

Good point @mschauer, I had forgotten about that. This is not exclusive to this PR, though -- comparison operators are broken for all Irrationals (and I've been meaning to submit a fix for that, but haven't had the time yet). Until the inequality operators are fixed for Irrationals in general, I don't think it's unreasonable to ignore them in Tau.jl for now.

@waldyrious
Copy link
Collaborator Author

@giordano I understand. I was hoping we could get this merged for Tau day, but I guess it'll have to wait for next year. I'll propose changes to Base before insisting further on this.

@mschauer
Copy link
Member

@waldyrious Thanks, I think that is a good idea.

@giordano
Copy link
Member

Anyway a new version of Tau.jl can still be tagged today, there have been quite some changes and fixes since last version ;-)

@waldyrious
Copy link
Collaborator Author

Good point, @giordano. I'll go ahead and tag a new version. Hopefully we can get it merged to METADATA.jl still today :)

@waldyrious
Copy link
Collaborator Author

@MasonProtter
Copy link

MasonProtter commented Mar 14, 2019

I actually kinda like the proposal to have

==(x::Irrational, y::T) where {T<:AbstractFloat} = T(x) == y
==(x::T, y::Irrational) where {T<:AbstractFloat} = x == T(y)

but if that never ends up in Base, then I'd argue that you just want to warn people that

julia> τ == 2π
false

is the wrong comparison to make and instead they should do the comparison

julia> 1τ == 2π
true

@devmotion
Copy link
Member

I'll close this PR as it is quite old, has conflicts with the main branch, and uses outdated syntax.

Regarding the proposed change, IMO Tau should be consistent with base, and the policy there hasn't changed (I think this policy is reasonable). Apart from the checks

julia> 1τ == 2π
true

or

julia> Float64(τ) == 2π
true

based on Float64, an alternative based on irrationals would be

julia> using IrrationalConstants

julia> τ == twoπ
true

Both constants are even identical objects 🙂

@devmotion devmotion closed this Feb 22, 2023
@giordano giordano deleted the wp/equality branch February 22, 2023 22:10
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.

5 participants