From 7b70f3c2c512c0ce5cb90a4673b47ac97195667b Mon Sep 17 00:00:00 2001 From: Mike Satteson Date: Sat, 31 Oct 2015 14:10:59 -0500 Subject: [PATCH 1/3] Documented abs overflow behavior, added checked_abs for overflow protection --- base/int.jl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/base/int.jl b/base/int.jl index 0ca47800f043c..6b845f09abef0 100644 --- a/base/int.jl +++ b/base/int.jl @@ -44,8 +44,33 @@ copysign(x::Signed, y::Float64) = copysign(x, reinterpret(Int64,y)) copysign(x::Signed, y::Real) = copysign(x, -oftype(x,signbit(y))) abs(x::Unsigned) = x + +""" + abs(x::Signed) + +The absolute value of x. When `abs` is applied to signed integers, +overflow may occur, resulting in the return of a negative value. This +overflow occurs only when `abs` is applied to the minimum +representable value of a signed integer. That is when `x == +typemin(typeof(x))`, `abs(x) == x`, not `-x` as might be expected. + +""" abs(x::Signed) = flipsign(x,x) +""" + checked_abs(x::Signed) + +The absolute value of x, with signed integer overflow error trapping. +`checked_abs` will throw an `OverflowError` when `x == +typemin(typeof(x))`. Otherwise `checked_abs` behaves as `abs`, though +the overflow protection may impose a perceptible performance penalty. + +""" +function checked_abs{T<:Signed}(x::T) + x == typemin(T) && throw(OverflowError()) + abs(x) +end + ~(n::Integer) = -n-1 unsigned(x::Signed) = reinterpret(typeof(convert(Unsigned,zero(x))), x) From 999ceb81c99ae53f7cf7fb37eb29939819ab6150 Mon Sep 17 00:00:00 2001 From: Mike Satteson Date: Sun, 1 Nov 2015 19:01:26 -0600 Subject: [PATCH 2/3] checked_abs, added testing. --- test/int.jl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/int.jl b/test/int.jl index 1ac3394795b6f..a2200ba8fb793 100644 --- a/test/int.jl +++ b/test/int.jl @@ -125,7 +125,7 @@ end # checked operations -import Base: checked_add, checked_sub, checked_mul +import Base: checked_add, checked_sub, checked_mul, checked_abs @test checked_sub(UInt(4), UInt(3)) === UInt(1) @test_throws OverflowError checked_sub(UInt(5), UInt(6)) @test checked_mul(UInt(4), UInt(3)) === UInt(12) @@ -138,6 +138,11 @@ else @test_throws OverflowError checked_mul(UInt(2)^62, UInt(2)^2) end +for T in SItypes + @test checked_abs(-one(T)) == one(T) + @test_throws OverflowError checked_abs(typemin(T)) +end + # Checked operations on UInt128 are currently broken # FIXME: #4905 @@ -153,3 +158,5 @@ end #@test_throws OverflowError checked_mul(UInt128(2)^127, UInt128(2)) @test checked_mul(UInt128(2)^127, UInt128(2)) === UInt128(0) # broken + + From fbf9331bc780faa27d717d3c26b92b48f820ce3a Mon Sep 17 00:00:00 2001 From: Mike Satteson Date: Sun, 1 Nov 2015 19:17:19 -0600 Subject: [PATCH 3/3] Removed trailing whitespace from test file. --- test/int.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/int.jl b/test/int.jl index a2200ba8fb793..919ca8a513a13 100644 --- a/test/int.jl +++ b/test/int.jl @@ -158,5 +158,3 @@ end #@test_throws OverflowError checked_mul(UInt128(2)^127, UInt128(2)) @test checked_mul(UInt128(2)^127, UInt128(2)) === UInt128(0) # broken - -