@@ -35,6 +35,8 @@ export checked_abs, checked_add, checked_cld, checked_div, checked_fld,
35
35
checked_mod, checked_mul, checked_neg, checked_rem, checked_sub
36
36
37
37
using Base: decompose, BitInteger
38
+
39
+ import BitIntegers # For 128-bit _widemul / _widen
38
40
import Parsers
39
41
40
42
# floats that support fma and are roughly IEEE-like
@@ -118,6 +120,21 @@ function __init__()
118
120
return
119
121
end
120
122
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
+
121
138
(:: Type{T} )(x:: Real ) where {T <: FD } = convert (T, x)
122
139
123
140
floattype (:: Type{<:FD{T}} ) where {T<: Union{Int8, UInt8, Int16, UInt16} } = Float32
@@ -157,7 +174,9 @@ function _round_to_nearest(quotient::T,
157
174
divisor:: T ,
158
175
:: RoundingMode{M} = RoundNearest) where {T <: Integer , M}
159
176
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
161
180
# `:NearestTiesAway` will tie away from zero, e.g. -8.5 ->
162
181
# -9. `:NearestTiesUp` will always ties towards positive
163
182
# 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).
188
207
# correctness test suite.
189
208
function Base.:* (x:: FD{T, f} , y:: FD{T, f} ) where {T, f}
190
209
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)
192
211
reinterpret (FD{T, f}, _round_to_nearest (quotient, remainder, powt))
193
212
end
194
213
@@ -416,7 +435,7 @@ function Base.checked_sub(x::T, y::T) where {T<:FD}
416
435
end
417
436
function Base. checked_mul (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
418
437
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)
420
439
v = _round_to_nearest (quotient, remainder, powt)
421
440
typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:* , x, y)
422
441
return reinterpret (FD{T, f}, T (v))
@@ -474,7 +493,7 @@ checked_rdiv(x::FD, y::FD) = checked_rdiv(promote(x, y)...)
474
493
475
494
function checked_rdiv (x:: FD{T,f} , y:: FD{T,f} ) where {T<: Integer ,f}
476
495
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)
478
497
v = _round_to_nearest (quotient, remainder, y. i)
479
498
typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
480
499
return reinterpret (FD{T, f}, v)
484
503
# FixedDecimal.
485
504
function checked_rdiv (x:: Integer , y:: FD{T, f} ) where {T<: Integer , f}
486
505
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)
489
508
v = _round_to_nearest (quotient, remainder, y. i)
490
509
typemin (T) <= v <= typemax (T) || Base. Checked. throw_overflowerr_binaryop (:/ , x, y)
491
510
reinterpret (FD{T, f}, v)
@@ -722,7 +741,7 @@ NOTE: This function is expensive, since it contains a while-loop, but it is actu
722
741
This function does not have or depend on any side-effects.
723
742
"""
724
743
function max_exp10 (:: Type{T} ) where {T <: Integer }
725
- W = widen (T)
744
+ W = _widen (T)
726
745
type_max = W (typemax (T))
727
746
728
747
powt = one (W)
@@ -759,4 +778,4 @@ value(fd::FD) = fd.i
759
778
# for generic hashing
760
779
Base. decompose (fd:: FD ) = decompose (Rational (fd))
761
780
762
- end
781
+ end # module
0 commit comments