Skip to content

Commit b923f29

Browse files
authored
Merge pull request #84 from JuliaMath/nhd-128-reduce-BigInts
Eliminate BigInt allocs for 128-bit FixedDecimal conversions.
2 parents 0e04214 + 958fe07 commit b923f29

File tree

4 files changed

+1132
-953
lines changed

4 files changed

+1132
-953
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "FixedPointDecimals"
22
uuid = "fb4d412d-6eee-574d-9565-ede6634db7b0"
33
authors = ["Fengyang Wang <fengyang.wang.0@gmail.com>", "Curtis Vogt <curtis.vogt@gmail.com>"]
4-
version = "0.4.3"
4+
version = "0.4.4"
55

66
[deps]
77
Parsers = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"

src/FixedPointDecimals.jl

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,35 @@ end
296296
Base.convert(::Type{FD{T, f}}, x::FD{T, f}) where {T, f} = x # Converting an FD to itself is a no-op
297297

298298
function Base.convert(::Type{FD{T, f}}, x::Integer) where {T, f}
299-
reinterpret(FD{T, f}, T(widemul(x, coefficient(FD{T, f}))))
299+
C = coefficient(FD{T, f})
300+
throw_inexact() = throw(InexactError(:convert, FD{T, f}, x))
301+
typemin(T) <= x <= typemax(T) || throw_inexact()
302+
xT = convert(T, x) # This won't throw, since we already checked, above.
303+
# Perform x * C, and check for overflow. This is cheaper than a widemul, especially for
304+
# 128-bit T, since those widen into a BigInt.
305+
v = _mul_checked_overflow(throw_inexact, xT, C)
306+
return reinterpret(FD{T, f}, v)
307+
end
308+
function Base.convert(::Type{FD{BigInt, f}}, x::Integer) where {f}
309+
# We specialize on f==0, since julia can't eliminate BigInt multiplication.
310+
if f == 0
311+
# If x is already a BigInt, this is a no-op, otherwise we alloc a new BigInt.
312+
return reinterpret(FD{BigInt, f}, BigInt(x))
313+
end
314+
# For the normal case, we multiply by C, which produces a BigInt value.
315+
C = coefficient(FD{BigInt, f})
316+
# This can't throw since BigInt and BigFloat can hold any number.
317+
v = x * C
318+
return reinterpret(FD{BigInt, f}, v)
319+
end
320+
321+
# x * y - if overflow, report an InexactError(FDT, )
322+
function _mul_checked_overflow(overflow_callback, x, y)
323+
v, overflow = Base.mul_with_overflow(x, y)
324+
if overflow
325+
overflow_callback()
326+
end
327+
return v
300328
end
301329

302330
Base.convert(::Type{T}, x::AbstractFloat) where {T <: FD} = round(T, x)
@@ -310,7 +338,10 @@ function Base.convert(::Type{FD{T, f}}, x::FD{U, g}) where {T, f, U, g}
310338
if f g
311339
# Compute `10^(f - g)` without overflow
312340
powt = div(coefficient(FD{T, f}), coefficient(FD{U, g}))
313-
reinterpret(FD{T, f}, T(widemul(x.i, powt)))
341+
v = _mul_checked_overflow(promote(x.i, powt)...) do
342+
throw(InexactError(:convert, FD{T, f}, x))
343+
end
344+
reinterpret(FD{T, f}, T(v))
314345
else
315346
# Compute `10^(g - f)` without overflow
316347
powt = div(coefficient(FD{U, g}), coefficient(FD{T, f}))

0 commit comments

Comments
 (0)