Skip to content

Commit e958121

Browse files
committed
Make convert errors more informative
1 parent 49934cd commit e958121

3 files changed

Lines changed: 38 additions & 14 deletions

File tree

src/FixedPointNumbers.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,13 @@ end
109109
const _log2_10 = 3.321928094887362
110110
showcompact{T,f}(io::IO, x::FixedPoint{T,f}) = show(io, round(convert(Float64,x), ceil(Int,f/_log2_10)))
111111

112+
@noinline function throw_converterror{T<:FixedPoint}(::Type{T}, x)
113+
n = 2^(8*sizeof(T))
114+
bitstring = sizeof(T) == 1 ? "an 8-bit" : "a $(8*sizeof(T))-bit"
115+
io = IOBuffer()
116+
showcompact(io, typemin(T)); Tmin = takebuf_string(io)
117+
showcompact(io, typemax(T)); Tmax = takebuf_string(io)
118+
throw(ArgumentError("$T is $bitstring type representing $n values from $Tmin to $Tmax; cannot represent $x"))
119+
end
120+
112121
end # module

src/ufixed.jl

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,27 @@ rawone(v) = reinterpret(one(v))
4141

4242
# Conversions
4343
convert{T<:UFixed}(::Type{T}, x::T) = x
44-
convert{T1<:UFixed}(::Type{T1}, x::UFixed) = reinterpret(T1, round(rawtype(T1), (rawone(T1)/rawone(x))*reinterpret(x)))
44+
function convert{T<:UFixed}(::Type{T}, x::UFixed)
45+
y = round((rawone(T)/rawone(x))*reinterpret(x))
46+
(0 <= y) & (y <= typemax(rawtype(T))) || throw_converterror(T, x)
47+
reinterpret(T, _unsafe_trunc(rawtype(T), y))
48+
end
4549
convert(::Type{UFixed16}, x::UFixed8) = reinterpret(UFixed16, convert(UInt16, 0x0101*reinterpret(x)))
4650
convert{U<:UFixed}(::Type{U}, x::Real) = _convert(U, rawtype(U), x)
47-
_convert{U<:UFixed,T}(::Type{U}, ::Type{T}, x) = U(round(T, widen1(rawone(U))*x), 0)
48-
_convert{U<:UFixed }(::Type{U}, ::Type{UInt128}, x) = U(round(UInt128, rawone(U)*x), 0)
51+
function _convert{U<:UFixed,T}(::Type{U}, ::Type{T}, x)
52+
y = round(widen1(rawone(U))*x)
53+
(0 <= y) & (y <= typemax(T)) || throw_converterror(U, x)
54+
U(_unsafe_trunc(T, y), 0)
55+
end
56+
function _convert{U<:UFixed}(::Type{U}, ::Type{UInt128}, x)
57+
y = round(rawone(U)*x) # for UInt128, we can't widen
58+
(0 <= y) & (y <= typemax(UInt128)) & (x <= Float64(typemax(U))) || throw_converterror(U, x)
59+
U(_unsafe_trunc(UInt128, y), 0)
60+
end
4961

5062
rem{T<:UFixed}(x::T, ::Type{T}) = x
51-
rem{T<:UFixed}(x::UFixed, ::Type{T}) = reinterpret(T, unsafe_trunc(rawtype(T), round((rawone(T)/rawone(x))*reinterpret(x))))
52-
rem{T<:UFixed}(x::Real, ::Type{T}) = reinterpret(T, unsafe_trunc(rawtype(T), round(rawone(T)*x)))
53-
rem{T<:UFixed}(x::Integer, ::Type{T}) = reinterpret(T, (rawone(T)*x) % rawtype(T)) # can be deleted once unsafe_trunc supports integer types (julia #18629)
63+
rem{T<:UFixed}(x::UFixed, ::Type{T}) = reinterpret(T, _unsafe_trunc(rawtype(T), round((rawone(T)/rawone(x))*reinterpret(x))))
64+
rem{T<:UFixed}(x::Real, ::Type{T}) = reinterpret(T, _unsafe_trunc(rawtype(T), round(rawone(T)*x)))
5465

5566
convert(::Type{BigFloat}, x::UFixed) = reinterpret(x)*(1/BigFloat(rawone(x)))
5667
function convert{T<:AbstractFloat}(::Type{T}, x::UFixed)
@@ -163,3 +174,6 @@ end
163174
end
164175
:(UFixed{$T,$f})
165176
end
177+
178+
_unsafe_trunc{T}(::Type{T}, x::Integer) = x % T
179+
_unsafe_trunc{T}(::Type{T}, x) = unsafe_trunc(T, x)

test/ufixed.jl

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@ end
4444
@test typemax(UFixed{UInt64,3}) == typemax(UInt64) // (2^3-1)
4545
@test typemax(UFixed{UInt128,7}) == typemax(UInt128) // (2^7-1)
4646

47-
@test_throws InexactError UFixed8(2)
48-
@test_throws InexactError UFixed8(255)
49-
@test_throws InexactError UFixed8(0xff)
50-
@test_throws InexactError UFixed16(2)
51-
@test_throws InexactError UFixed16(0xff)
52-
@test_throws InexactError UFixed16(0xffff)
53-
@test_throws InexactError convert(UFixed8, typemax(UFixed10))
54-
@test_throws InexactError convert(UFixed16, typemax(UFixed10))
47+
# TODO: change back to InexactError when it allows message strings
48+
@test_throws ArgumentError UFixed8(2)
49+
@test_throws ArgumentError UFixed8(255)
50+
@test_throws ArgumentError UFixed8(0xff)
51+
@test_throws ArgumentError UFixed16(2)
52+
@test_throws ArgumentError UFixed16(0xff)
53+
@test_throws ArgumentError UFixed16(0xffff)
54+
@test_throws ArgumentError convert(UFixed8, typemax(UFixed10))
55+
@test_throws ArgumentError convert(UFixed16, typemax(UFixed10))
5556

5657
x = UFixed8(0.5)
5758
@test isfinite(x) == true

0 commit comments

Comments
 (0)