@@ -35,6 +35,8 @@ export checked_abs, checked_add, checked_cld, checked_div, checked_fld,
3535 checked_mod, checked_mul, checked_neg, checked_rem, checked_sub
3636
3737using Base: decompose, BitInteger
38+
39+ import BitIntegers # For 128-bit _widemul / _widen
3840import Parsers
3941
4042# floats that support fma and are roughly IEEE-like
@@ -118,6 +120,21 @@ function __init__()
118120 return
119121end
120122
123+ # Custom widemul implementation to avoid the cost of widening to BigInt.
124+ # FD{Int128} operations should widen to 256 bits internally, rather than to a BigInt.
125+ const BitInteger128 = Union{Int128, UInt128}
126+ _widemul (x, y) = _widen (x) * _widen (y)
127+ _widemul (x:: Signed ,y:: Unsigned ) = _widen (x) * signed (_widen (y))
128+ _widemul (x:: Unsigned ,y:: Signed ) = signed (_widen (x)) * _widen (y)
129+
130+ # Custom widen implementation to avoid the cost of widening to BigInt.
131+ # FD{Int128} operations should widen to 256 bits internally, rather than to a BigInt.
132+ _widen (:: Type{Int128} ) = BitIntegers. Int256
133+ _widen (:: Type{UInt128} ) = BitIntegers. UInt256
134+ _widen (t:: Type ) = widen (t)
135+ _widen (x:: T ) where {T} = (_widen (T))(x)
136+
137+
121138(:: Type{T} )(x:: Real ) where {T <: FD } = convert (T, x)
122139
123140floattype (:: Type{<:FD{T}} ) where {T<: Union{Int8, UInt8, Int16, UInt16} } = Float32
@@ -157,7 +174,9 @@ function _round_to_nearest(quotient::T,
157174 divisor:: T ,
158175 :: RoundingMode{M} = RoundNearest) where {T <: Integer , M}
159176 halfdivisor = divisor >> 1
160- if iseven (divisor) && remainder == halfdivisor
177+ # PERF Note: Only need the last bit to check iseven, and default iseven(Int256)
178+ # allocates, so we truncate first.
179+ if iseven ((divisor % Int8)) && remainder == halfdivisor
161180 # `:NearestTiesAway` will tie away from zero, e.g. -8.5 ->
162181 # -9. `:NearestTiesUp` will always ties towards positive
163182 # infinity. `:Nearest` will tie towards the nearest even
@@ -188,7 +207,7 @@ _round_to_nearest(q, r, d, m=RoundNearest) = _round_to_nearest(promote(q, r, d).
188207# correctness test suite.
189208function Base.:* (x:: FD{T, f} , y:: FD{T, f} ) where {T, f}
190209 powt = coefficient (FD{T, f})
191- quotient, remainder = fldmodinline (widemul (x. i, y. i), powt)
210+ quotient, remainder = fldmodinline (_widemul (x. i, y. i), powt)
192211 reinterpret (FD{T, f}, _round_to_nearest (quotient, remainder, powt))
193212end
194213
@@ -416,7 +435,7 @@ function Base.checked_sub(x::T, y::T) where {T<:FD}
416435end
417436function Base. checked_mul (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
418437 powt = coefficient (FD{T, f})
419- quotient, remainder = fldmodinline (widemul (x. i, y. i), powt)
438+ quotient, remainder = fldmodinline (_widemul (x. i, y. i), powt)
420439 v = _round_to_nearest (quotient, remainder, powt)
421440 typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:* , x, y)
422441 return reinterpret (FD{T, f}, T (v))
@@ -474,7 +493,7 @@ checked_rdiv(x::FD, y::FD) = checked_rdiv(promote(x, y)...)
474493
475494function checked_rdiv (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
476495 powt = coefficient (FD{T, f})
477- quotient, remainder = fldmod (widemul (x. i, powt), y. i)
496+ quotient, remainder = fldmod (_widemul (x. i, powt), y. i)
478497 v = _round_to_nearest (quotient, remainder, y. i)
479498 typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
480499 return reinterpret (FD{T, f}, v)
484503# FixedDecimal.
485504function checked_rdiv (x:: Integer , y:: FD{T, f} ) where {T<: Integer , f}
486505 powt = coefficient (FD{T, f})
487- powtsq = widemul (powt, powt)
488- quotient, remainder = fldmod (widemul (x, powtsq), y. i)
506+ powtsq = _widemul (powt, powt)
507+ quotient, remainder = fldmod (_widemul (x, powtsq), y. i)
489508 v = _round_to_nearest (quotient, remainder, y. i)
490509 typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
491510 reinterpret (FD{T, f}, v)
@@ -722,7 +741,7 @@ NOTE: This function is expensive, since it contains a while-loop, but it is actu
722741 This function does not have or depend on any side-effects.
723742"""
724743function max_exp10 (:: Type{T} ) where {T <: Integer }
725- W = widen (T)
744+ W = _widen (T)
726745 type_max = W (typemax (T))
727746
728747 powt = one (W)
@@ -759,4 +778,4 @@ value(fd::FD) = fd.i
759778# for generic hashing
760779Base. decompose (fd:: FD ) = decompose (Rational (fd))
761780
762- end
781+ end # module
0 commit comments