From d3a3d955c4ce805edc64574c0aa1439a3f2cbbd9 Mon Sep 17 00:00:00 2001 From: Simon Byrne Date: Wed, 24 Sep 2014 11:23:01 +0100 Subject: [PATCH] fix float vs rational comparisons --- base/float.jl | 4 ++ base/hashing2.jl | 95 +++++++++++++++++++++++++++++++++++++++++++++++ base/int.jl | 4 ++ base/intfuncs.jl | 4 ++ base/mpfr.jl | 7 ++++ base/promotion.jl | 3 +- base/rational.jl | 10 +---- test/numbers.jl | 10 +++++ 8 files changed, 127 insertions(+), 10 deletions(-) diff --git a/base/float.jl b/base/float.jl index a43243daf9f081..fd0cba3ba4c6f4 100644 --- a/base/float.jl +++ b/base/float.jl @@ -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)) diff --git a/base/hashing2.jl b/base/hashing2.jl index af0ae10189b530..25d5a2aa6e209a 100644 --- a/base/hashing2.jl +++ b/base/hashing2.jl @@ -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 diff --git a/base/int.jl b/base/int.jl index fa3d5f81b18759..0a457c9d330194 100644 --- a/base/int.jl +++ b/base/int.jl @@ -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)) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 9c11e2798935cb..9ec400eda479b4 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -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) diff --git a/base/mpfr.jl b/base/mpfr.jl index 11635d6becffcb..0b37ac5dff28d1 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -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) diff --git a/base/promotion.jl b/base/promotion.jl index a3879cd1cb3114..e70dfddcfdc137 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -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)...) @@ -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) diff --git a/base/rational.jl b/base/rational.jl index a830368cf2e311..4d4af1b7b1e6ff 100644 --- a/base/rational.jl +++ b/base/rational.jl @@ -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) @@ -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) diff --git a/test/numbers.jl b/test/numbers.jl index 6e8b9408f27fcc..7ed1d0e43abf26 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -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