Skip to content

Commit

Permalink
Fix rounding for Rational with return type Bool or Integer. Added mor…
Browse files Browse the repository at this point in the history
…e tests for Rationals.
  • Loading branch information
pkofod committed Feb 26, 2016
1 parent 420fdc3 commit a88dbae
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 13 deletions.
36 changes: 30 additions & 6 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -289,35 +289,59 @@ floor{T}(::Type{T}, x::Rational) = convert(T,fld(x.num,x.den))
ceil{ T}(::Type{T}, x::Rational) = convert(T,cld(x.num,x.den))


function round{Tf, Tr}(::Type{Tf}, x::Rational{Tr}, ::RoundingMode{:Nearest})
function round{T, Tr}(::Type{T}, x::Rational{Tr}, ::RoundingMode{:Nearest})
if den(x) == zero(Tr) && T <: Integer
throw(DivideError())
elseif den(x) == zero(Tr)
return convert(T, copysign(one(Tr)//zero(Tr), num(x)))
end
q,r = divrem(num(x), den(x))
s = q
if abs(r) >= abs((den(x)-copysign(Tr(4), num(x))+one(Tr)+iseven(q))>>1 + copysign(Tr(2), num(x)))
s += copysign(one(Tr),num(x))
end
convert(Tf, s)
convert(T, s)
end

round{T}(::Type{T}, x::Rational) = round(T, x, RoundNearest)

function round{Tf, Tr}(::Type{Tf}, x::Rational{Tr}, ::RoundingMode{:NearestTiesAway})
function round{T, Tr}(::Type{T}, x::Rational{Tr}, ::RoundingMode{:NearestTiesAway})
if den(x) == zero(Tr) && T <: Integer
throw(DivideError())
elseif den(x) == zero(Tr)
return convert(T, copysign(one(Tr)//zero(Tr), num(x)))
end
q,r = divrem(num(x), den(x))
s = q
if abs(r) >= abs((den(x)-copysign(Tr(4), num(x))+one(Tr))>>1 + copysign(Tr(2), num(x)))
s += copysign(one(Tr),num(x))
end
convert(Tf, s)
convert(T, s)
end

function round{Tf, Tr}(::Type{Tf}, x::Rational{Tr}, ::RoundingMode{:NearestTiesUp})
function round{T, Tr}(::Type{T}, x::Rational{Tr}, ::RoundingMode{:NearestTiesUp})
if den(x) == zero(Tr) && T <: Integer
throw(DivideError())
elseif den(x) == zero(Tr)
return convert(T, copysign(one(Tr)//zero(Tr), num(x)))
end
q,r = divrem(num(x), den(x))
s = q
if abs(r) >= abs((den(x)-copysign(Tr(4), num(x))+one(Tr)+(num(x)<0))>>1 + copysign(Tr(2), num(x)))
s += copysign(one(Tr),num(x))
end
convert(Tf, s)
convert(T, s)
end

function round{T}(::Type{T}, x::Rational{Bool})
if den(x) == false && issubtype(T, Union{Integer, Bool})
throw(DivideError())
end
convert(T, x)
end

round{T}(::Type{T}, x::Rational{Bool}, ::RoundingMode) = round(T, x)

trunc{T}(x::Rational{T}) = Rational(trunc(T,x))
floor{T}(x::Rational{T}) = Rational(floor(T,x))
ceil{ T}(x::Rational{T}) = Rational(ceil(T,x))
Expand Down
34 changes: 27 additions & 7 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2782,9 +2782,6 @@ for Tf = (Float16, Float32, Float64), Ti = (Int16, Int32, Int64)
over_half = Rational(div(typemax(Ti),Ti(2))+one(Ti), typemax(Ti))
exactly_half = Rational(one(Ti) , Ti(2))

@test round(Tf, Rational(1,2), RoundNearestTiesUp) == 1.0
@test round(Tf, Rational(1,2), RoundNearestTiesAway) == 1.0

@test round( almost_half) == 0//1
@test round(-almost_half) == 0//1
@test round(Tf, almost_half, RoundNearestTiesUp) == 0.0
Expand All @@ -2811,6 +2808,17 @@ for Tf = (Float16, Float32, Float64), Ti = (Int16, Int32, Int64)
@test round(Tf, -11//2, RoundNearestTiesUp) == -5.0
@test round(Tf, 11//2, RoundNearestTiesAway) == 6.0
@test round(Tf, -11//2, RoundNearestTiesAway) == -6.0

@test round(Tf, Ti(-1)//zero(Ti)) == -Inf
@test round(Tf, one(1)//zero(Ti)) == Inf
@test round(Tf, Ti(-1)//zero(Ti), RoundNearestTiesUp) == -Inf
@test round(Tf, one(1)//zero(Ti), RoundNearestTiesUp) == Inf
@test round(Tf, Ti(-1)//zero(Ti), RoundNearestTiesAway) == -Inf
@test round(Tf, one(1)//zero(Ti), RoundNearestTiesAway) == Inf

@test round(Tf, zero(Ti)//one(Ti)) == 0
@test round(Tf, zero(Ti)//one(Ti), RoundNearestTiesUp) == 0
@test round(Tf, zero(Ti)//one(Ti), RoundNearestTiesAway) == 0
end

let
Expand All @@ -2832,7 +2840,19 @@ let
end
end

@test round(11//2) == 6 # rounds to closest _even_ integer
@test round(-11//2) == -6 # rounds to closest _even_ integer
@test round(11//3) == 4 # rounds to closest _even_ integer
@test round(-11//3) == -4 # rounds to closest _even_ integer
@test round(11//2) == 6//1 # rounds to closest _even_ integer
@test round(-11//2) == -6//1 # rounds to closest _even_ integer
@test round(11//3) == 4//1 # rounds to closest _even_ integer
@test round(-11//3) == -4//1 # rounds to closest _even_ integer

for T in (Float16, Float32, Float64)
@test round(T, true//false) === convert(T, Inf)
@test round(T, true//true) === one(T)
@test round(T, false//true) === zero(T)
end

for T in (Int8, Int16, Int32, Int64, Bool)
@test_throws DivideError round(T, true//false)
@test round(T, true//true) === one(T)
@test round(T, false//true) === zero(T)
end

0 comments on commit a88dbae

Please sign in to comment.