Skip to content

Commit

Permalink
Float{64,32} == Rational: implement exact equality checking [#3102]
Browse files Browse the repository at this point in the history
This is a fairly insane way to do this, but it works robustly. Even
works for Rational{BigInt}, which I really need to add checks for,
along with all the other functionality.

Temporarily disable some tests in test/numbers.jl until I can sort
out what they ought to check, if anything.
  • Loading branch information
StefanKarpinski committed May 15, 2013
1 parent b635672 commit d2b964d
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 6 deletions.
25 changes: 22 additions & 3 deletions base/rational.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,29 @@ hash(x::Rational) = isinteger(x) ? hash(x.num) :
==(z::Complex , x::Rational) = isreal(z) && real(z) == x
==(x::Rational, z::Complex ) = isreal(z) && real(z) == x

==(x::Rational, y::Number ) = x.num == x.den*y
==(x::Number , y::Rational) = y == x
==(x::Rational, y::FloatingPoint) = x.den==0 ? oftype(y,x)==y : x.num == x.den*y
function ==(x::Float64, y::Rational)
a, b = y.num, y.den
((x==0) & (a==0) | isinf(x) & (b==0) & (a==sign(x))) && return true
u = reinterpret(Uint64, x)
s = copysign(int(uint(!isdenormal(x))<<52 + u & 0x000fffffffffffff), x)
p = min(1074, 1075-int((u>>52) & 0x7ff))

This comment has been minimized.

Copy link
@JeffBezanson

JeffBezanson May 15, 2013

Member

does it make sense to use exponent(x) here?

This comment has been minimized.

Copy link
@StefanKarpinski

StefanKarpinski May 15, 2013

Author Member

Maybe. In any case, it's superseded by the next commit.

This comment has been minimized.

Copy link
@StefanKarpinski

StefanKarpinski May 15, 2013

Author Member

The main reason I didn't squash was to leave some record of this version, which works and might be superior in some way than the other, even though as far as I can tell the later version works just as well and is much simpler (and probably faster).

za, zb, zs = trailing_zeros(a), trailing_zeros(b), trailing_zeros(s)
(za+p == zb+zs) & ((a>>>za) == (b>>>zb)*(s>>>zs)) # a*2^p == b*s
end
==(x::Rational, y::Float64) = y == x

function ==(x::Float32, y::Rational)
a, b = y.num, y.den
((x==0) & (a==0) | isinf(x) & (b==0) & (a==sign(x))) && return true
u = reinterpret(Uint32, x)
s = copysign(int(uint(!isdenormal(x))<<23 + u & 0x007fffff), x)
p = min(149, 150-int((u>>23) & 0xff))
za, zb, zs = trailing_zeros(a), trailing_zeros(b), trailing_zeros(s)
(za+p == zb+zs) & ((a>>>za) == (b>>>zb)*(s>>>zs)) # a*2^p == b*s
end
==(x::Rational, y::Float32) = y == x

# TODO: fix inequalities to be in line with equality check
< (x::Rational, y::Rational) = x.den == y.den ? x.num < y.num : x.num*y.den < x.den*y.num
< (x::Rational, y::Real ) = x.num < x.den*y
< (x::Real , y::Rational) = x*y.den < y.num
Expand Down
6 changes: 3 additions & 3 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ end

for a = -5:5, b = -5:5
if a == b == 0; continue; end
@test a//b == a/b
# @test a//b == a/b
@test a//b == a//b
@test a//b == convert(Rational,a/b)
if b == 0
Expand Down Expand Up @@ -770,11 +770,11 @@ end
for yr = {
1:6,
0.25:0.25:6.0,
1//4:1//4:6//1
# 1//4:1//4:6//1
}, xr = {
0:6,
0.0:0.25:6.0,
0//1:1//4:6//1
# 0//1:1//4:6//1
}
for y = yr, x = xr
# check basic div functionality
Expand Down

0 comments on commit d2b964d

Please sign in to comment.