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

Fixing abs for Rational{<:Unsigned} #29561

Merged
merged 5 commits into from
Oct 9, 2018
Merged

Fixing abs for Rational{<:Unsigned} #29561

merged 5 commits into from
Oct 9, 2018

Conversation

lcontento
Copy link
Contributor

I noticed that calling abs for values of type Rational{<:Unsigned} results in an OverflowError being raised. E.g., in Julia 1.0.1 I get

julia> abs(one(Rational{UInt}))
ERROR: OverflowError: cannot negate unsigned number
Stacktrace:
 [1] - at ./rational.jl:240 [inlined]
 [2] abs(::Rational{UInt64}) at ./number.jl:144
 [3] top-level scope at none:0

Since abs(x::Real) in number.jl uses ifelse, it tries to compute -x which is not possible for x::Rational{<:Unsigned}. A possible solution for this problem is specializing abs like

Base.abs(x::Rational{<:Unsigned}) = x

as done in this pull request.

@fredrikekre fredrikekre added domain:rationals The Rational type and values thereof kind:bugfix This change fixes an existing bug backport pending 1.0 labels Oct 8, 2018
Copy link
Member

@fredrikekre fredrikekre left a comment

Choose a reason for hiding this comment

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

Thanks for a great first contribution! Welcome!

base/rational.jl Outdated
@@ -226,6 +226,8 @@ signbit(x::Rational) = signbit(x.num)
copysign(x::Rational, y::Real) = copysign(x.num,y) // x.den
copysign(x::Rational, y::Rational) = copysign(x.num,y.num) // x.den

abs(x::Rational{T}) where {T<:Unsigned} = x
Copy link
Member

Choose a reason for hiding this comment

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

An alternative approach (and maybe more general?) would be to define

abs(x::Rational) = Rational(abs(x.num), x.den)

but I don't know what is best.
I also wonder if the ifelse in numbers.jl could simply be a ternary, i.e.

abs(x::Real) = signbit(x) ? -x : x

since, as noted in this PR, not all numbers can be negated.

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

When T is unsigned, it is true that the ratio cannot be negative, so I guess this is fine. It's a bit weird to be using unsigned integers for rationals in the first place though, isn't it? I do think that @fredrikekre's suggestion for a generic definition that works for all rationals by calling abs on the numerator is better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed @fredrikekre's proposal appears to be more general. Should I add another commit to the same PR making the change or resubmit a cleaner one?

By the way, I was using unsigned rationals since it is a possible tag type for EXIF metadata. I agree that they are a strange choice in a general use case.

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

Just add more commits here. Much easier that way. We can squash it when it’s ready.


@test abs(one(Rational{UInt})) === one(Rational{UInt})
@test abs(one(Rational{Int})) === one(Rational{Int})
@test abs(-one(Rational{Int})) === one(Rational{Int})
Copy link
Member

Choose a reason for hiding this comment

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

Would be good to add a comment to reference this PR just above the tests. The two last tests seems unrelated to the PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are perfectly right. Just the first test is related to the bug. However, I did not find other tests regarding the abs method, so I thought that checking that the signed version works too would be useful. I admit I have not much experience about writing testcases, so if you think the tests should be kept to a minimum I will remove the last two.

Copy link
Sponsor Member

Choose a reason for hiding this comment

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

These seem fine to me. The main thing is to test it and I don’t mind having a slightly unrelated test added as well.

@lcontento
Copy link
Contributor Author

Happy to help! Even if it's just a very small bug ;-)

@StefanKarpinski
Copy link
Sponsor Member

Not at all! It’s great to have it noticed and fixed.

Copy link
Sponsor Member

@StefanKarpinski StefanKarpinski left a comment

Choose a reason for hiding this comment

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

CI Failures look unrelated; I've restarted the ones that failed.

@martinholters martinholters merged commit 4eb1a93 into JuliaLang:master Oct 9, 2018
KristofferC pushed a commit that referenced this pull request Oct 9, 2018
* Fix abs for Rational{<:Unsigned}

* Add tests for abs(x::Rational)

(cherry picked from commit 4eb1a93)
KristofferC pushed a commit that referenced this pull request Oct 10, 2018
* Fix abs for Rational{<:Unsigned}

* Add tests for abs(x::Rational)

(cherry picked from commit 4eb1a93)
KristofferC pushed a commit that referenced this pull request Feb 11, 2019
* Fix abs for Rational{<:Unsigned}

* Add tests for abs(x::Rational)

(cherry picked from commit 4eb1a93)
KristofferC pushed a commit that referenced this pull request Feb 20, 2020
* Fix abs for Rational{<:Unsigned}

* Add tests for abs(x::Rational)

(cherry picked from commit 4eb1a93)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:rationals The Rational type and values thereof kind:bugfix This change fixes an existing bug
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants