Skip to content

Commit 83e0b42

Browse files
committed
Fix convert(::Type{FD}, ::FD) at the input limits
1 parent 3d9332b commit 83e0b42

File tree

2 files changed

+35
-11
lines changed

2 files changed

+35
-11
lines changed

src/FixedPointDecimals.jl

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,14 +217,17 @@ end
217217

218218
function convert{T, f, U, g}(::Type{FD{T, f}}, x::FD{U, g})
219219
if f g
220-
reinterpret(FD{T, f}, convert(T, Base.widemul(T(10)^(f-g), x.i)))
220+
# Compute `10^(f - g)` without overflow
221+
powt = div(coefficient(FD{T, f}), coefficient(FD{U, g}))
222+
reinterpret(FD{T, f}, T(widemul(x.i, powt)))
221223
else
222-
sf = T(10)^(g - f)
223-
q, r = divrem(x.i, sf)
224-
if r 0
225-
throw(InexactError())
224+
# Compute `10^(g - f)` without overflow
225+
powt = div(coefficient(FD{U, g}), coefficient(FD{T, f}))
226+
q, r = divrem(x.i, powt)
227+
if r == 0
228+
reinterpret(FD{T, f}, T(q))
226229
else
227-
reinterpret(FD{T, f}, convert(T, q))
230+
throw(InexactError())
228231
end
229232
end
230233
end

test/runtests.jl

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ end
100100
end
101101
end
102102

103+
@testset "invalid" begin
104+
@test_throws InexactError convert(FD2, FD4(0.0001))
105+
@test_throws InexactError convert(FD4, typemax(FD2))
106+
@test_throws InexactError convert(SFD2, typemax(FD2))
107+
@test_throws InexactError convert(FD2, 1//3)
108+
@test_throws InexactError convert(FD{Int8,1}, 1//4)
109+
end
110+
103111
@testset "limits of $T" for T in CONTAINER_TYPES
104112
f = FixedPointDecimals.max_exp10(T) + 1
105113
powt = FixedPointDecimals.coefficient(FD{T,f})
@@ -136,11 +144,24 @@ end
136144
@test_throws InexactError convert(FD{T,f}, min_int ÷ powt - T(1)) # Overflows with Unsigned
137145
end
138146

139-
@test_throws InexactError convert(FD2, FD4(0.0001))
140-
@test_throws InexactError convert(FD4, typemax(FD2))
141-
@test_throws InexactError convert(SFD2, typemax(FD2))
142-
@test_throws InexactError convert(FD2, 1//3)
143-
@test_throws InexactError convert(FD{Int8,1}, 1//4)
147+
@testset "limits from $U to $T" for T in CONTAINER_TYPES, U in CONTAINER_TYPES
148+
f = FixedPointDecimals.max_exp10(T) + 1
149+
g = FixedPointDecimals.max_exp10(U) + 1
150+
powt = div(
151+
FixedPointDecimals.coefficient(FD{T, f}),
152+
FixedPointDecimals.coefficient(FD{U, g}),
153+
)
154+
155+
val = typemax(U)
156+
expected = widemul(typemax(U), powt)
157+
158+
# Mixed usage of signed and unsigned types makes testing with typemin hard.
159+
if f >= g && expected <= typemax(T)
160+
@test convert(FD{T,f}, reinterpret(FD{U,g}, val)) == reinterpret(FD{T,f}, expected)
161+
else
162+
@test_throws InexactError convert(FD{T,f}, reinterpret(FD{U,g}, val))
163+
end
164+
end
144165
end
145166

146167
@testset "promotion" begin

0 commit comments

Comments
 (0)