@@ -5,7 +5,7 @@ using DecFP_jll
55
66import 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
1010const _buffer = Vector {Vector{UInt8}} ()
1111
@@ -238,6 +238,19 @@ function isnanstr(s::AbstractString)
238238 return false
239239end
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)
268281for 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
589623end
@@ -595,7 +629,7 @@ Base.convert(::Type{Integer}, x::DecimalFloatingPoint) = convert(Int, x)
595629function 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))
600634end
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
665699end
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-
706701function Base.:(== )(dec:: DecimalFloatingPoint , rat:: Rational )
707702 if isfinite (dec)
708703 rat. den == 1 && return dec == rat. num
0 commit comments