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

Overflow when rounding rationals in edge case #15215

Closed
pkofod opened this issue Feb 24, 2016 · 5 comments · Fixed by #15227
Closed

Overflow when rounding rationals in edge case #15215

pkofod opened this issue Feb 24, 2016 · 5 comments · Fixed by #15227

Comments

@pkofod
Copy link
Contributor

pkofod commented Feb 24, 2016

Rounding rationals uses the good ol' right bit shift

function round{T}(::Type{T}, x::Rational, ::RoundingMode{:Nearest})
    q,r = divrem(x.num,x.den)
    s = abs(r) < (x.den+one(x.den)+iseven(q))>>1 ? q : q+copysign(one(q),x.num)
    convert(T,s)
end
round{T}(::Type{T}, x::Rational) = round(T,x,RoundNearest)
function round{T}(::Type{T}, x::Rational, ::RoundingMode{:NearestTiesAway})
    q,r = divrem(x.num,x.den)
    s = abs(r) < (x.den+one(x.den))>>1 ? q : q+copysign(one(q),x.num)
    convert(T,s)
end
function round{T}(::Type{T}, x::Rational, ::RoundingMode{:NearestTiesUp})
    q,r = divrem(x.num,x.den)
    s = abs(r) < (x.den+one(x.den)+(x.num<0))>>1 ? q : q+copysign(one(q),x.num)
    convert(T,s)
end

This is fine, except the +one(x.den) addition gives a problematic edge case, when x.den == typemax(T) where T = typeof(x.den). It's problematic because it overflows, and we get:

julia> r = Rational(rand(Int32)), typemax(Int32))
234//2147483647
julia> round(r)
1//1

The result is independent of the realization of rand(IntType) as the overflow will happen no matter what, resulting in a negative rounded half denominator which is always strictly smaller than abs(r). This means that even if you get 1//1 when num>den it is not because of a correct calculation, but a buggy result, that coincides with the correct answer.

I would love to fix it, but I'm not sure what people would prefer. I know it is not Matlab, and Julia doesn't warn users of typemax(::Type)+one(::Type), but in round() we can actually find the answer if we are careful in how we compare when den(r)==typemax(typeof(r)). It will come with a perf cost, but I guess the round of a Rational is rarely important performance wise.

@simonbyrne
Copy link
Contributor

This should certainly be fixed. For Rationals we generally favour correctness over performance optimisations.

@pkofod
Copy link
Contributor Author

pkofod commented Feb 24, 2016

I'll submit a pr later then.

@simonbyrne
Copy link
Contributor

Fantastic, thanks!

@pkofod
Copy link
Contributor Author

pkofod commented Feb 24, 2016

I'll make a PR soon, but I just have a style question. In the current code, the numerator and denominator are retrived as:

x.num
x.den

but wouldn't functions (they are already defined!) be more Julian than dots?

num(x)
den(x)

?

@simonbyrne
Copy link
Contributor

Yes, particularly if we make the changes discussed in #11522

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.

2 participants