Skip to content

Commit fab4079

Browse files
authored
Improve overflow error message (#214)
This displays the fixed point type of the input in the message, not the rawtype. This also avoids the stall with `checked_{add/sub}` on Windows.
1 parent b7e2ae1 commit fab4079

File tree

3 files changed

+27
-10
lines changed

3 files changed

+27
-10
lines changed

src/FixedPointNumbers.jl

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,19 @@ saturating_sub(x::X, y::X) where {X <: FixedPoint} =
200200
saturating_sub(x::X, y::X) where {X <: FixedPoint{<:Unsigned}} = X(x.i - min(x.i, y.i), 0)
201201

202202
# checked arithmetic
203-
checked_neg(x::X) where {X <: FixedPoint} = X(checked_neg(x.i), 0)
204-
checked_add(x::X, y::X) where {X <: FixedPoint} = X(checked_add(x.i, y.i), 0)
205-
checked_sub(x::X, y::X) where {X <: FixedPoint} = X(checked_sub(x.i, y.i), 0)
203+
checked_neg(x::X) where {X <: FixedPoint} = checked_sub(zero(X), x)
204+
function checked_add(x::X, y::X) where {X <: FixedPoint}
205+
r, f = Base.Checked.add_with_overflow(x.i, y.i)
206+
z = X(r, 0) # store first
207+
f && throw_overflowerror(:+, x, y)
208+
z
209+
end
210+
function checked_sub(x::X, y::X) where {X <: FixedPoint}
211+
r, f = Base.Checked.sub_with_overflow(x.i, y.i)
212+
z = X(r, 0) # store first
213+
f && throw_overflowerror(:-, x, y)
214+
z
215+
end
206216

207217
# default arithmetic
208218
const DEFAULT_ARITHMETIC = :wrapping
@@ -424,6 +434,13 @@ scaledual(::Type{Tdual}, x::AbstractArray{T}) where {Tdual, T <: FixedPoint} =
424434
throw(ArgumentError(String(take!(io))))
425435
end
426436

437+
@noinline function throw_overflowerror(op::Symbol, @nospecialize(x), @nospecialize(y))
438+
io = IOBuffer()
439+
print(io, x, ' ', op, ' ', y, " overflowed for type ")
440+
showtype(io, typeof(x))
441+
throw(OverflowError(String(take!(io))))
442+
end
443+
427444
function Random.rand(r::AbstractRNG, ::SamplerType{X}) where X <: FixedPoint
428445
X(rand(r, rawtype(X)), 0)
429446
end

test/fixed.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ end
275275
xs = typemin(F):eps(F):typemax(F)
276276
fneg(x) = -float(x)
277277
@test all(x -> wrapping_neg(wrapping_neg(x)) === x, xs)
278-
@test all(x -> saturating_neg(x) == clamp(fneg(x), F), xs)
279-
@test all(x -> !(typemin(F) < fneg(x) < typemax(F)) ||
278+
@test all(x -> saturating_neg(x) === clamp(fneg(x), F), xs)
279+
@test all(x -> !(typemin(F) <= fneg(x) <= typemax(F)) ||
280280
wrapping_neg(x) === checked_neg(x) === fneg(x) % F, xs)
281281
end
282282
end
@@ -301,8 +301,8 @@ end
301301
xys = ((x, y) for x in xs, y in xs)
302302
fadd(x, y) = float(x) + float(y)
303303
@test all(((x, y),) -> wrapping_sub(wrapping_add(x, y), y) === x, xys)
304-
@test all(((x, y),) -> saturating_add(x, y) == clamp(fadd(x, y), F), xys)
305-
@test all(((x, y),) -> !(typemin(F) < fadd(x, y) < typemax(F)) ||
304+
@test all(((x, y),) -> saturating_add(x, y) === clamp(fadd(x, y), F), xys)
305+
@test all(((x, y),) -> !(typemin(F) <= fadd(x, y) <= typemax(F)) ||
306306
wrapping_add(x, y) === checked_add(x, y) === fadd(x, y) % F, xys)
307307
end
308308
end

test/normed.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ end
303303
fneg(x) = -float(x)
304304
@test all(x -> wrapping_neg(wrapping_neg(x)) === x, xs)
305305
@test all(x -> saturating_neg(x) === clamp(fneg(x), N), xs)
306-
@test all(x -> !(typemin(N) < fneg(x) < typemax(N)) ||
306+
@test all(x -> !(typemin(N) <= fneg(x) <= typemax(N)) ||
307307
wrapping_neg(x) === checked_neg(x) === fneg(x) % N, xs)
308308
end
309309
end
@@ -329,7 +329,7 @@ end
329329
fadd(x, y) = float(x) + float(y)
330330
@test all(((x, y),) -> wrapping_sub(wrapping_add(x, y), y) === x, xys)
331331
@test all(((x, y),) -> saturating_add(x, y) === clamp(fadd(x, y), N), xys)
332-
@test all(((x, y),) -> !(typemin(N) < fadd(x, y) < typemax(N)) ||
332+
@test all(((x, y),) -> !(typemin(N) <= fadd(x, y) <= typemax(N)) ||
333333
wrapping_add(x, y) === checked_add(x, y) === fadd(x, y) % N, xys)
334334
end
335335
end
@@ -354,7 +354,7 @@ end
354354
fsub(x, y) = float(x) - float(y)
355355
@test all(((x, y),) -> wrapping_add(wrapping_sub(x, y), y) === x, xys)
356356
@test all(((x, y),) -> saturating_sub(x, y) === clamp(fsub(x, y), N), xys)
357-
@test all(((x, y),) -> !(typemin(N) < fsub(x, y) < typemax(N)) ||
357+
@test all(((x, y),) -> !(typemin(N) <= fsub(x, y) <= typemax(N)) ||
358358
wrapping_sub(x, y) === checked_sub(x, y) === fsub(x, y) % N, xys)
359359
end
360360
end

0 commit comments

Comments
 (0)