Skip to content

Commit b573c0b

Browse files
authored
add BigFloat support (#7)
1 parent 1d55d1d commit b573c0b

File tree

2 files changed

+118
-13
lines changed

2 files changed

+118
-13
lines changed

src/Quadmath.jl

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ import Base: (*), +, -, /, <, <=, ==, ^, convert,
1313
exp, expm1, log, log2, log10, log1p, sin, sinh, sqrt,
1414
tan, tanh,
1515
ceil, floor, trunc, round, fma,
16-
copysign, max, min, hypot,
17-
abs, imag, real, conj, angle, cis,
18-
eps, isinf, isnan, isfinite,
19-
Int32,Int64,Float64
16+
copysign, max, min, hypot, abs,
17+
ldexp, frexp,
18+
eps, isinf, isnan, isfinite, floatmin, floatmax, precision, signbit,
19+
Int32,Int64,Float64,BigFloat
2020

2121
if Sys.isapple()
2222
const quadoplib = "libquadmath.0"
@@ -185,11 +185,12 @@ isinf(x::Float128) =
185185
isfinite(x::Float128) =
186186
0 != ccall((:finiteq,libquadmath), Cint, (Cfloat128, ), x)
187187

188-
eps(::Type{Float128}) = reinterpret(Float128, 0x3f8f0000000000000000000000000000)
189-
realmin(::Type{Float128}) = reinterpret(Float128, 0x00010000000000000000000000000000)
190-
realmax(::Type{Float128}) = reinterpret(Float128, 0x7ffeffffffffffffffffffffffffffff)
191-
Float128(::Irrational{:π}) = reinterpret(Float128, 0x4000921fb54442d18469898cc51701b8)
192-
Float128(::Irrational{:e}) = reinterpret(Float128, 0x40005bf0a8b1457695355fb8ac404e7a)
188+
signbit(x::Float128) = signbit(reinterpret(Int128, x))
189+
precision(::Type{Float128}) = 113
190+
191+
eps(::Type{Float128}) = reinterpret(Float128, 0x3f8f_0000_0000_0000_0000_0000_0000_0000)
192+
floatmin(::Type{Float128}) = reinterpret(Float128, 0x0001_0000_0000_0000_0000_0000_0000_0000)
193+
floatmax(::Type{Float128}) = reinterpret(Float128, 0x7ffe_ffff_ffff_ffff_ffff_ffff_ffff_ffff)
193194

194195

195196
ldexp(x::Float128, n::Cint) =
@@ -199,10 +200,105 @@ ldexp(x::Float128, n::Integer) =
199200

200201
function frexp(x::Float128)
201202
r = Ref{Cint}()
202-
Float128(ccall((:frexpq, libquadmath), Cfloat128, (Cfloat128, Ptr{Cint}), x, r))
203-
return x, Int(r[])
203+
y = Float128(ccall((:frexpq, libquadmath), Cfloat128, (Cfloat128, Ptr{Cint}), x, r))
204+
return y, Int(r[])
204205
end
205206

207+
Float128(::Irrational{:π}) = reinterpret(Float128, 0x4000921fb54442d18469898cc51701b8)
208+
Float128(::Irrational{:e}) = reinterpret(Float128, 0x40005bf0a8b1457695355fb8ac404e7a)
209+
210+
function BigFloat(x::Float128; precision=precision(BigFloat))
211+
if !isfinite(x) || iszero(x)
212+
@static if VERSION < v"1.1"
213+
return BigFloat(Float64(x), precision)
214+
else
215+
return BigFloat(Float64(x), precision=precision)
216+
end
217+
end
218+
219+
@static if VERSION < v"1.1"
220+
b = setprecision(BigFloat, max(precision,113)) do
221+
BigFloat()
222+
end
223+
else
224+
b = BigFloat(precision=max(precision,113))
225+
end
226+
227+
y, k = frexp(x)
228+
b.exp = Clong(k)
229+
b.sign = signbit(x) ? Cint(-1) : Cint(1)
230+
u = (reinterpret(UInt128, y) << 15) | 0x8000_0000_0000_0000_0000_0000_0000_0000
231+
i = cld(precision, sizeof(Culong)*8)
232+
while u != 0
233+
w = (u >> (128-sizeof(Culong)*8)) % Culong
234+
unsafe_store!(b.d, w, i)
235+
i -= 1
236+
u <<= sizeof(Culong)*8
237+
end
238+
# set remaining bits to zero
239+
while i > 0
240+
unsafe_store!(b.d, zero(Culong), i)
241+
i -= 1
242+
end
243+
244+
if precision < 113
245+
@static if VERSION < v"1.1"
246+
b2 = setprecision(BigFloat, precision) do
247+
BigFloat()
248+
end
249+
ccall((:mpfr_set, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32),
250+
b2, b, Base.MPFR.ROUNDING_MODE[])
251+
return b2
252+
else
253+
return BigFloat(b, precision=precision)
254+
end
255+
else
256+
return b
257+
end
258+
end
259+
260+
function Float128(x::BigFloat)
261+
if !isfinite(x) || iszero(x)
262+
return Float128(Float64(x))
263+
end
264+
265+
y,k = frexp(x)
266+
if k >= -16381
267+
prec = 113
268+
elseif k >= -16381-112
269+
prec = 113 + (k + 16381)
270+
elseif k == -16381-113 && abs(y) > 0.5
271+
z = reinterepret(Float128, UInt128(1))
272+
else
273+
z = reinterepret(Float128, UInt128(0))
274+
end
275+
276+
@static if VERSION < v"1.1"
277+
y = setprecision(BigFloat, prec) do
278+
BigFloat()
279+
end
280+
ccall((:mpfr_set, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Int32),
281+
y, x, Base.MPFR.ROUNDING_MODE[])
282+
else
283+
y = BigFloat(x, precision=prec)
284+
end
285+
286+
u = zero(UInt128)
287+
i = cld(prec, sizeof(Culong)*8)
288+
j = 113
289+
while i > 0
290+
j -= sizeof(Culong)*8
291+
u |= (unsafe_load(y.d, i) % UInt128) << j
292+
i -= 1
293+
end
294+
u &= significand_mask(Float128)
295+
u |= exponent_half(Float128)
296+
z = ldexp(reinterpret(Float128, u), y.exp)
297+
return copysign(z,x)
298+
end
299+
300+
301+
206302
promote_rule(::Type{Float128}, ::Type{Float16}) = Float128
207303
promote_rule(::Type{Float128}, ::Type{Float32}) = Float128
208304
promote_rule(::Type{Float128}, ::Type{Float64}) = Float128

test/runtests.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
using Test
22
using Quadmath
33

4-
for T in (Float64, Int32, Int64)
4+
@testset "conversion $T" for T in (Float64, Int32, Int64, BigFloat)
55
@test Float128(T(1)) + Float128(T(2)) == Float128(T(3))
66
@test Float128(T(1)) + Float128(T(2)) <= Float128(T(3))
77
@test Float128(T(1)) + Float128(T(2)) != Float128(T(4))
88
@test Float128(T(1)) + Float128(T(2)) < Float128(T(4))
9-
@test T(Float128(T(1)) + Float128(T(2))) === T(3)
9+
if isbitstype(T)
10+
@test T(Float128(T(1)) + Float128(T(2))) === T(3)
11+
end
1012
end
1113

1214
@test Base.exponent_one(Float128) == reinterpret(UInt128, Float128(1.0))
15+
16+
@testset "BigFloat" begin
17+
x = parse(Float128, "0.1")
18+
y = parse(Float128, "0.2")
19+
@test Float64(x+y) == Float64(BigFloat(x) + BigFloat(y))
20+
@test x+y == Float128(BigFloat(x) + BigFloat(y))
21+
end

0 commit comments

Comments
 (0)