Skip to content

Commit 1521136

Browse files
authored
extend Base.decompose so hashing and comparison to rationals work (#44)
* extend Base.decompose so hashing works * add tests of rational comparisons
1 parent faba57e commit 1521136

File tree

3 files changed

+110
-1
lines changed

3 files changed

+110
-1
lines changed

src/Quadmath.jl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Base: (*), +, -, /, <, <=, ==, ^, convert,
1111
acos, acosh, asin, asinh, atan, atanh, cosh, cos, sincos,
1212
exp, expm1, log, log2, log10, log1p, sin, sinh, sqrt,
1313
tan, tanh,
14-
ceil, floor, trunc, round, fma,
14+
ceil, floor, trunc, round, fma, decompose,
1515
copysign, flipsign, max, min, hypot, abs,
1616
ldexp, frexp, modf, nextfloat, typemax, typemin, eps,
1717
isinf, isnan, isfinite, isinteger,
@@ -564,6 +564,17 @@ promote_rule(::Type{Float128}, ::Type{<:Integer}) = Float128
564564
#widen(::Type{Float64}) = Float128
565565
widen(::Type{Float128}) = BigFloat
566566

567+
function decompose(x::Float128)::Tuple{Int128, Int, Int}
568+
isnan(x) && return 0, 0, 0
569+
isinf(x) && return ifelse(x < 0, -1, 1), 0, 0
570+
n = reinterpret(UInt128, x)
571+
s = (n & significand_mask(Float128)) % Int128
572+
e = ((n & exponent_mask(Float128)) >> 112) % Int
573+
s |= Int128(e != 0) << 112
574+
d = ifelse(signbit(x), -1, 1)
575+
s, e - 16495 + (e == 0), d
576+
end
577+
567578
function Random.rand(rng::AbstractRNG, s::Random.SamplerTrivial{Random.CloseOpen01{Float128}})
568579
u = rand(rng, UInt128)
569580
x = (reinterpret(Float128, u & Base.significand_mask(Float128)

test/hashing.jl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# extend hashing tests from Julia Base to Float128
2+
3+
hashtypes = Any[
4+
Bool,
5+
Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64, Float128,
6+
Rational{Int8}, Rational{UInt8}, Rational{Int16}, Rational{UInt16},
7+
Rational{Int32}, Rational{UInt32}, Rational{Int64}, Rational{UInt64}
8+
]
9+
hashvals = vcat(
10+
typemin(Int64),
11+
-Int64(maxintfloat(Float64)) .+ Int64[-4:1;],
12+
typemin(Int32),
13+
-Integer(maxintfloat(Float32)) .+ (-4:1),
14+
-2:2,
15+
Integer(maxintfloat(Float32)) .+ (-1:4),
16+
typemax(Int32),
17+
Int64(maxintfloat(Float64)) .+ Int64[-1:4;],
18+
typemax(Int64),
19+
)
20+
21+
function coerce(T::Type, x)
22+
if T<:Rational
23+
convert(T, coerce(typeof(numerator(zero(T))), x))
24+
elseif !(T<:Integer)
25+
convert(T, x)
26+
else
27+
x % T
28+
end
29+
end
30+
31+
@testset "hash 0,1" begin
32+
for x = hashvals,
33+
a = coerce(Float128, x)
34+
@test hash(a,zero(UInt)) == invoke(hash, Tuple{Real, UInt}, a, zero(UInt))
35+
@test hash(a,one(UInt)) == invoke(hash, Tuple{Real, UInt}, a, one(UInt))
36+
end
37+
end
38+
39+
@testset "hashing" begin
40+
for T = hashtypes,
41+
S = hashtypes,
42+
x = hashvals,
43+
a = coerce(T, x),
44+
b = coerce(S, x)
45+
T == Float128 || S == Float128 || continue # other types are not our problem
46+
#println("$(typeof(a)) $a")
47+
#println("$(typeof(b)) $b")
48+
@test isequal(a,b) == (hash(a)==hash(b))
49+
end
50+
end

test/runtests.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,54 @@ end
180180
@test abs((2*Float128(MathConstants.golden) - 1)^2 - 5) < 5 * tiny
181181
end
182182

183+
@testset "rationals" begin
184+
@test Float128(0.5) == 1//2
185+
# onetenth = 1/Float128(10)
186+
# apparently identical, but do the same as Base test:
187+
onetenth = parse(Float128, "0.1")
188+
@test onetenth != 1//10
189+
# bias + log2(1/8):
190+
a = Int128(1) << 115
191+
# rounding as indicated by BigFloat:
192+
@test onetenth == (a ÷ 10 + 1) // a
193+
@test Inf128 == 1//0
194+
@test -Inf128 == -1//0
195+
fm = floatmin(Float128)
196+
@test fm != 1//(BigInt(2)^16382+1)
197+
@test fm == 1//(BigInt(2)^16382)
198+
@test fm != 1//(BigInt(2)^16382-1)
199+
@test fm/2 != 1//(BigInt(2)^16383+1)
200+
@test fm/2 == 1//(BigInt(2)^16383)
201+
@test fm/2 != 1//(BigInt(2)^16383-1)
202+
tiny = nextfloat(Float128(0.0))
203+
@test tiny != 1//(BigInt(2)^16494+1)
204+
@test tiny == 1//(BigInt(2)^16494)
205+
@test tiny != 1//(BigInt(2)^16494-1)
206+
207+
onethird = 1/Float128(3)
208+
onefifth = 1/Float128(5)
209+
@test onethird < 1//3
210+
@test !(1//3 < onethird)
211+
@test -onethird < 1//3
212+
@test -onethird > -1//3
213+
@test onethird > -1//3
214+
@test onefifth > 1//5
215+
@test 1//3 < Inf128
216+
@test 0//1 < Inf128
217+
@test 1//0 == Inf128
218+
@test -1//0 == -Inf128
219+
@test -1//0 != Inf128
220+
@test 1//0 != -Inf128
221+
@test !(1//0 < Inf128)
222+
Zero = Float128(0)
223+
fnan = Zero / Zero
224+
@test !(1//3 < fnan)
225+
@test !(1//3 == fnan)
226+
@test !(1//3 > fnan)
227+
end
228+
229+
include("hashing.jl")
230+
183231
include("specfun.jl")
184232

185233
include("printf.jl")

0 commit comments

Comments
 (0)