Skip to content

Commit 78ed076

Browse files
authored
Export sigexp (#138)
1 parent 10dfa6b commit 78ed076

File tree

2 files changed

+50
-45
lines changed

2 files changed

+50
-45
lines changed

src/DecFP.jl

Lines changed: 40 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ using DecFP_jll
55

66
import Printf, Random, SpecialFunctions
77

8-
export Dec32, Dec64, Dec128, @d_str, @d32_str, @d64_str, @d128_str, exponent10, ldexp10
8+
export Dec32, Dec64, Dec128, @d_str, @d32_str, @d64_str, @d128_str, exponent10, ldexp10, sigexp
99

1010
const _buffer = Vector{Vector{UInt8}}()
1111

@@ -238,6 +238,19 @@ function isnanstr(s::AbstractString)
238238
return false
239239
end
240240

241+
"""
242+
sigexp(x::DecFP.DecimalFloatingPoint)
243+
244+
Return `(sign, significand, exponent)` such that `x` is equal to `sign * significand * 10^exponent`.
245+
Throws `DomainError` for infinite or `NaN` arguments.
246+
247+
# Examples
248+
```jldoctest
249+
julia> sigexp(Dec64(1.25))
250+
(1, 125, -2)
251+
```
252+
"""
253+
sigexp(x::DecimalFloatingPoint)
241254

242255
"""
243256
exponent10(x::DecFP.DecimalFloatingPoint)
@@ -268,6 +281,7 @@ ldexp10(x::DecFP.DecimalFloatingPoint, n::Integer)
268281
for w in (32,64,128)
269282
BID = Symbol(string("Dec",w))
270283
Ti = eval(Symbol(string("UInt",w)))
284+
Tsi = eval(Symbol(string("Int",w)))
271285
T = eval(BID)
272286

273287
# hack: we need an internal parsing function that doesn't check exceptions, since
@@ -439,6 +453,26 @@ for w in (32,64,128)
439453
return Int32(n), Int32(pt), neg
440454
end
441455

456+
function sigexp(x::$BID)
457+
isnan(x) && throw(DomainError(x, "sigexp(x) is not defined for NaN."))
458+
isinf(x) && throw(DomainError(x, "sigexp(x) is only defined for finite x."))
459+
p = 9 * $w ÷ 32 - 2
460+
emax = 3 * 2^($w ÷ 16 + 3)
461+
bias = emax + p - 2
462+
ebits = $w ÷ 16 + 6
463+
sbits = $w - ebits - 1
464+
n = reinterpret($Ti, x)
465+
if n & $Ti(0x3) << ($w - 3) == $Ti(0x3) << ($w - 3)
466+
s = ((n & typemax($Ti) >> (ebits + 3)) | one($Ti) << sbits) % $Tsi
467+
e = ((n & typemax($Ti) << (sbits + 1) >> 3) >> (sbits - 2)) % Int
468+
else
469+
s = (n & typemax($Ti) >> (ebits + 1)) % $Tsi
470+
e = ((n & typemax($Ti) << (sbits + 1) >> 1) >> sbits) % Int
471+
end
472+
e -= bias
473+
return signbit(x) ? -1 : 1, s, e
474+
end
475+
442476
Base.fma(x::$BID, y::$BID, z::$BID) = nox(ccall(($(bidsym(w,"fma")), libbid), $BID, ($BID,$BID,$BID,Cuint,Ref{Cuint}), x, y, z, roundingmode[Threads.threadid()], RefArray(flags, Threads.threadid())))
443477
Base.muladd(x::$BID, y::$BID, z::$BID) = fma(x,y,z) # faster than x+y*z
444478

@@ -583,7 +617,7 @@ for (f) in (:trunc, :floor, :ceil)
583617
@eval function Base.$f(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer}
584618
x′ = $f(x)
585619
typemin(I) <= x′ <= typemax(I) || throw(InexactError(Symbol($f), I, x))
586-
s, e = sigexp(x′)
620+
_, s, e = sigexp(x′)
587621
return I(flipsign(s * I(10)^e, x))
588622
end
589623
end
@@ -595,7 +629,7 @@ Base.convert(::Type{Integer}, x::DecimalFloatingPoint) = convert(Int, x)
595629
function Base.convert(::Type{I}, x::DecimalFloatingPoint) where {I<:Integer}
596630
x != trunc(x) && throw(InexactError(:convert, I, x))
597631
typemin(I) <= x <= typemax(I) || throw(InexactError(:convert, I, x))
598-
s, e = sigexp(x)
632+
_, s, e = sigexp(x)
599633
return I(flipsign(s * I(10)^e, x))
600634
end
601635

@@ -641,12 +675,12 @@ function Base.decompose(x::DecimalFloatingPoint)::Tuple{BigInt, Int, BigInt}
641675
isnan(x) && return 0, 0, 0
642676
isinf(x) && return ifelse(signbit(x), -1, 1), 0, 0
643677
iszero(x) && return 0, 0, ifelse(signbit(x), -1, 1)
644-
s, e = sigexp(x)
678+
sign, s, e = sigexp(x)
645679
if e >= 0
646680
if e <= 27
647-
return s * BigInt(Int64(5)^e), e, ifelse(signbit(x), -1, 1)
681+
return s * BigInt(Int64(5)^e), e, sign
648682
else
649-
return s * BigInt(5)^e, e, ifelse(signbit(x), -1, 1)
683+
return s * BigInt(5)^e, e, sign
650684
end
651685
else
652686
e2 = -e
@@ -664,45 +698,6 @@ function Base.decompose(x::DecimalFloatingPoint)::Tuple{BigInt, Int, BigInt}
664698
end
665699
end
666700

667-
function sigexp(x::Dec32)
668-
n = reinterpret(UInt32, x)
669-
if n & 0x60000000 == 0x60000000
670-
s = ((n & 0x001fffff) | 0x00800000) % Int32
671-
e = ((n & 0x1fe00000) >> 21) % Int
672-
else
673-
s = (n & 0x007fffff) % Int32
674-
e = ((n & 0x7f800000) >> 23) % Int
675-
end
676-
e -= 101
677-
return s, e
678-
end
679-
680-
function sigexp(x::Dec64)
681-
n = reinterpret(UInt64, x)
682-
if n & 0x6000000000000000 == 0x6000000000000000
683-
s = ((n & 0x0007ffffffffffff) | 0x0020000000000000) % Int64
684-
e = ((n & 0x1ff8000000000000) >> 51) % Int
685-
else
686-
s = (n & 0x001fffffffffffff) % Int64
687-
e = ((n & 0x7fe0000000000000) >> 53) % Int
688-
end
689-
e -= 398
690-
return s, e
691-
end
692-
693-
function sigexp(x::Dec128)
694-
n = reinterpret(UInt128, x)
695-
if n & 0x60000000000000000000000000000000 == 0x60000000000000000000000000000000
696-
s = ((n & 0x00007fffffffffffffffffffffffffff) | 0x00020000000000000000000000000000) % Int128
697-
e = ((n & 0x1fff8000000000000000000000000000) >> 111) % Int
698-
else
699-
s = (n & 0x0001ffffffffffffffffffffffffffff) % Int128
700-
e = ((n & 0x7ffe0000000000000000000000000000) >> 113) % Int
701-
end
702-
e -= 6176
703-
return s, e
704-
end
705-
706701
function Base.:(==)(dec::DecimalFloatingPoint, rat::Rational)
707702
if isfinite(dec)
708703
rat.den == 1 && return dec == rat.num

test/runtests.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,16 @@ for T in (Dec32, Dec64, Dec128)
183183
x,y,z = 1.5, -3.25, 0.0625 # exactly represented in binary
184184
xd = T(x); yd = T(y); zd = T(z)
185185

186+
@test_throws DomainError sigexp(T(NaN))
187+
@test_throws DomainError sigexp(T(Inf))
188+
@test_throws DomainError sigexp(T(-Inf))
189+
@test sigexp(T(0)) == (1, 0, 0)
190+
@test sigexp(T("-0")) == (-1, 0, 0)
191+
@test sigexp(T(1)) == (1, 1, 0)
192+
@test sigexp(T(-1)) == (-1, 1, 0)
193+
@test sigexp(T(-1.25)) == (-1, 125, -2)
194+
@test sigexp(maxintfloat(T) - 1) == (1, Int128(maxintfloat(T) - 1), 0)
195+
186196
@test fma(xd,yd,zd)::T == muladd(xd,yd,zd)::T == xd*yd+zd == fma(x,y,z)
187197

188198
@test one(T)::T == 1

0 commit comments

Comments
 (0)