Skip to content

Commit

Permalink
fix float vs rational comparisons
Browse files Browse the repository at this point in the history
  • Loading branch information
simonbyrne committed Sep 24, 2014
1 parent 13c6917 commit d3a3d95
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 10 deletions.
4 changes: 4 additions & 0 deletions base/float.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ cld{T<:FloatingPoint}(x::T, y::T) = -fld(-x,y)
mod{T<:FloatingPoint}(x::T, y::T) = rem(y+rem(x,y),y)

## floating point comparisons ##
==(x::FloatingPoint, y::FloatingPoint) = (==)(promote(x,y)...)
< (x::FloatingPoint, y::FloatingPoint) = (< )(promote(x,y)...)
<=(x::FloatingPoint, y::FloatingPoint) = (<=)(promote(x,y)...)


==(x::Float32, y::Float32) = eq_float(unbox(Float32,x),unbox(Float32,y))
==(x::Float64, y::Float64) = eq_float(unbox(Float64,x),unbox(Float64,y))
Expand Down
95 changes: 95 additions & 0 deletions base/hashing2.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,98 @@ function hash(r::Range, h::Uint)
h = hash(step(r), h)
h = hash(last(r), h)
end


## Fallback comparisons for reals
#=
Non-finite comparisons:
x y == < <=
NaN ? . . .
? NaN . . .
+Inf +Inf t . t
+Inf R . . .
+Inf -Inf . . .
-Inf +Inf . t t
-Inf R . t t
-Inf -Inf t . t
R +Inf . t t
R -Inf . . .
=#

function ==(x::Real, y::Real)
xnf, ynf = !isfinite(x), !isfinite(y)
if xnf || ynf
(isnan(x) || isnan(y)) && return false
(xnf && ynf && sign(x) == sign(y)) && return true
return false
end
xs, ys = int(sign(x)), int(sign(y))
xs != ys && return false
xs == 0 && return true

xn, xp, xd = decompose(x)
yn, yp, yd = decompose(y)
xc, yc = widemul(xn,yd), widemul(yn,xd)
xb, yb = nbits(xc) + xp, nbits(yc) + yp

(xb == yb) && begin
xc, yc = promote(xc,yc)
if xp > yp
(xc<<(xp-yp)) == yc
else
xc == (yc<<(yp-xp))
end
end
end

function <(x::Real, y::Real)
xnf, ynf = !isfinite(x), !isfinite(y)
if xnf || ynf
(isnan(x) || isnan(y)) && return false
((xnf && sign(x) > 0) || (ynf && sign(y) < 0)) && return false
return true
end
xs, ys = int(sign(x)), int(sign(y))
xs < ys && return true
xs > ys && return false
xs == 0 && return false

xn, xp, xd = decompose(x)
yn, yp, yd = decompose(y)
xc, yc = xs*widemul(xn,yd), ys*widemul(yn,xd)
xb, yb = nbits(xc) + xp, nbits(yc) + yp
(xb*xs < yb*ys) || (xb == yb) && begin
xc, yc = promote(xc,yc)
if xp > yp
(xc<<(xp-yp)) < yc
else
xc < (yc<<(yp-xp))
end
end
end

function <=(x::Real, y::Real)
xnf, ynf = !isfinite(x), !isfinite(y)
if xnf || ynf
(isnan(x) || isnan(y)) && return false
((xnf && sign(x) < 0) || (ynf && sign(y) > 0)) && return true
return false
end
xs, ys = int(sign(x)), int(sign(y))
xs < ys && return true
xs > ys && return false
xs == 0 && return true

xn, xp, xd = decompose(x)
yn, yp, yd = decompose(y)
xc, yc = xs*widemul(xn,yd), ys*widemul(yn,xd)
xb, yb = nbits(xc) + xp, nbits(yc) + yp
(xb*xs < yb*ys) || (xb == yb) && begin
xc, yc = promote(xc,yc)
if xp > yp
(xc<<(xp-yp)) <= yc
else
xc <= (yc<<(yp-xp))
end
end
end
4 changes: 4 additions & 0 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,10 @@ leading_ones (x::Integer) = leading_zeros(~x)
trailing_ones(x::Integer) = trailing_zeros(~x)

## integer comparisons ##
< (x::Integer, y::Integer) = (< )(promote(x,y)...)
<=(x::Integer, y::Integer) = (<=)(promote(x,y)...)
==(x::Integer, y::Integer) = (==)(promote(x,y)...)
=={T<:Integer}(x::T, y::T) = x === y

<(x::Int8, y::Int8) = slt_int(unbox(Int8,x),unbox(Int8,y))
<(x::Int16, y::Int16) = slt_int(unbox(Int16,x),unbox(Int16,y))
Expand Down
4 changes: 4 additions & 0 deletions base/intfuncs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ ndigits(x::Unsigned) = x==0 ? 1 : ndigits0z(x)
ndigits(x::Integer, b::Integer) = b >= 0 ? ndigits(unsigned(abs(x)),int(b)) : ndigitsnb(x, b)
ndigits(x::Integer) = ndigits(unsigned(abs(x)))

nbits(x::Integer) = ndigits(x,2) # fallback
nbits(x::Unsigned) = x == 0 ? 1 : 8*sizeof(x)-leading_zeros(x)
nbits(x::Signed) = x == 0 ? 1 : 8*sizeof(x)-leading_zeros(abs(x))

## integer to string functions ##

function bin(x::Unsigned, pad::Int, neg::Bool)
Expand Down
7 changes: 7 additions & 0 deletions base/mpfr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,13 @@ end
<=(i::BigInt, f::BigFloat) = !isnan(f) && !(f < i)
<=(f::BigFloat, i::BigInt) = !isnan(f) && !(i < f)

==(i::Integer,f::BigFloat) = big(i) == f
==(f::BigFloat,i::Integer) = f == big(i)
<(i::Integer,f::BigFloat) = big(i) < f
<(f::BigFloat,i::Integer) = f < big(i)
<=(i::Integer,f::BigFloat) = big(i) <= f
<=(f::BigFloat,i::Integer) = f <= big(i)

signbit(x::BigFloat) = ccall((:mpfr_signbit, :libmpfr), Int32, (Ptr{BigFloat},), &x) != 0

function precision(x::BigFloat)
Expand Down
3 changes: 1 addition & 2 deletions base/promotion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ promote_to_super{T<:Number,S<:Number}(::Type{T}, ::Type{S}, ::Type) =
($)(x::Integer, y::Integer) = ($)(promote(x,y)...)

==(x::Number, y::Number) = (==)(promote(x,y)...)
< (x::Real, y::Real) = (< )(promote(x,y)...)
<=(x::Real, y::Real) = (<=)(promote(x,y)...)

div(x::Real, y::Real) = div(promote(x,y)...)
fld(x::Real, y::Real) = fld(promote(x,y)...)
Expand Down Expand Up @@ -197,6 +195,7 @@ no_op_err(name, T) = error(name," not defined for ",T)
($){T<:Integer}(x::T, y::T) = no_op_err("\$", T)

=={T<:Number}(x::T, y::T) = x === y
=={T<:Real}(x::T, y::T) = x === y
<{T<:Real}(x::T, y::T) = no_op_err("<", T)

max{T<:Real}(x::T, y::T) = ifelse(y < x, x, y)
Expand Down
10 changes: 2 additions & 8 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ typemin{T<:Integer}(::Type{Rational{T}}) = -one(T)//zero(T)
typemax{T<:Integer}(::Type{Rational{T}}) = one(T)//zero(T)

isinteger(x::Rational) = x.den == 1
isinf(x::Rational) = x.den == 0
isfinite(x::Rational) = x.den != 0

-(x::Rational) = (-x.num) // x.den
for op in (:+, :-, :rem, :mod)
Expand All @@ -155,23 +157,15 @@ end
==(z::Complex , x::Rational) = isreal(z) & (real(z) == x)
==(x::Rational, z::Complex ) = isreal(z) & (real(z) == x)

==(x::FloatingPoint, q::Rational) = count_ones(q.den) <= 1 & (x == q.num/q.den) & (x*q.den == q.num)
==(q::Rational, x::FloatingPoint) = count_ones(q.den) <= 1 & (x == q.num/q.den) & (x*q.den == q.num)

# TODO: fix inequalities to be in line with equality check
< (x::Rational, y::Rational) = x.den == y.den ? x.num < y.num :
widemul(x.num,y.den) < widemul(x.den,y.num)
< (x::Rational, y::Integer ) = x.num < widemul(x.den,y)
< (x::Rational, y::Real ) = x.num < x.den*y
< (x::Integer , y::Rational) = widemul(x,y.den) < y.num
< (x::Real , y::Rational) = x*y.den < y.num

<=(x::Rational, y::Rational) = x.den == y.den ? x.num <= y.num :
widemul(x.num,y.den) <= widemul(x.den,y.num)
<=(x::Rational, y::Integer ) = x.num <= widemul(x.den,y)
<=(x::Rational, y::Real ) = x.num <= x.den*y
<=(x::Integer , y::Rational) = widemul(x,y.den) <= y.num
<=(x::Real , y::Rational) = x*y.den <= y.num

div(x::Rational, y::Rational) = div(x.num*y.den, x.den*y.num)
div(x::Rational, y::Real ) = div(x.num, x.den*y)
Expand Down
10 changes: 10 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,16 @@ end
@test nextfloat(0.0) == 1//(BigInt(2)^1074)
@test nextfloat(0.0) != 1//(BigInt(2)^1074-1)

@test 1/3 < 1//3
@test !(1//3 < 1/3)
@test -1/3 < 1//3
@test -1/3 > -1//3
@test 1/3 > -1//3
@test 1//3 < Inf
@test 0//1 < Inf
@test !(1//0 < Inf)
@test !(1//3 < NaN)

@test sqrt(2) == 1.4142135623730951

@test 1+1.5 == 2.5
Expand Down

0 comments on commit d3a3d95

Please sign in to comment.