Skip to content

Commit

Permalink
get numbers test passing with checked integer conversions and type-st…
Browse files Browse the repository at this point in the history
…able arithmetic
  • Loading branch information
JeffBezanson committed Sep 17, 2014
1 parent effff39 commit 1d5050b
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 83 deletions.
4 changes: 4 additions & 0 deletions base/char.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ char(x::FloatingPoint) = char(iround(x))

integer(x::Char) = int(x)

convert(::Type{Char}, x::Float16) = char(convert(Uint32, x))
convert(::Type{Char}, x::Float32) = char(convert(Uint32, x))
convert(::Type{Char}, x::Float64) = char(convert(Uint32, x))

## char promotions ##

promote_rule(::Type{Char}, ::Type{Int8}) = Int32
Expand Down
10 changes: 5 additions & 5 deletions base/float.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
## conversions to floating-point ##

convert(::Type{Float32}, x::Int128) = float32(uint128(abs(x)))*(1-2(x<0))
convert(::Type{Float32}, x::Uint128) = float32(uint64(x)) + ldexp(float32(uint64(x>>>64)),64)
convert(::Type{Float32}, x::Int128) = float32(reinterpret(Uint128,abs(x)))*(1-2(x<0))
convert(::Type{Float32}, x::Uint128) = float32(uint64(x&0xffffffffffffffff)) + ldexp(float32(uint64(x>>>64)),64)
promote_rule(::Type{Float32}, ::Type{Int128} ) = Float32
promote_rule(::Type{Float32}, ::Type{Uint128}) = Float32

convert(::Type{Float64}, x::Int128) = float64(uint128(abs(x)))*(1-2(x<0))
convert(::Type{Float64}, x::Uint128) = float64(uint64(x)) + ldexp(float64(uint64(x>>>64)),64)
convert(::Type{Float64}, x::Int128) = float64(reinterpret(Uint128,abs(x)))*(1-2(x<0))
convert(::Type{Float64}, x::Uint128) = float64(uint64(x&0xffffffffffffffff)) + ldexp(float64(uint64(x>>>64)),64)
promote_rule(::Type{Float64}, ::Type{Int128} ) = Float64
promote_rule(::Type{Float64}, ::Type{Uint128}) = Float64

convert(::Type{Float16}, x::Union(Signed,Unsigned)) = convert(Float16, convert(Float32,x))
convert(::Type{Float16}, x::Integer) = convert(Float16, convert(Float32,x))
for t in (Bool,Char,Int8,Int16,Int32,Int64,Uint8,Uint16,Uint32,Uint64)
@eval promote_rule(::Type{Float16}, ::Type{$t}) = Float32
end
Expand Down
97 changes: 34 additions & 63 deletions base/int.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
## type aliases ##

if Int === Int32
typealias SmallSigned Union(Int8,Int16)
typealias SmallUnsigned Union(Uint8,Uint16)
else
typealias SmallSigned Union(Int8,Int16,Int32)
typealias SmallUnsigned Union(Uint8,Uint16,Uint32)
end

## integer arithmetic ##

const IntTypes = (Int8, Uint8, Int16, Uint16, Int32, Uint32,
Expand All @@ -34,11 +24,10 @@ iseven(n::Integer) = !isodd(n)
signbit(x::Integer) = x < 0
signbit(x::Unsigned) = false

flipsign(x::Int, y::Int) = box(Int,flipsign_int(unbox(Int,x),unbox(Int,y)))
flipsign(x::Int64, y::Int64) = box(Int64,flipsign_int(unbox(Int64,x),unbox(Int64,y)))
flipsign(x::Int128, y::Int128) = box(Int128,flipsign_int(unbox(Int128,x),unbox(Int128,y)))
for T in (Int8,Int16,Int32,Int64,Int128)
@eval flipsign(x::$T, y::$T) = box($T,flipsign_int(unbox($T,x),unbox($T,y)))
end

flipsign{T<:Signed}(x::T,y::T) = flipsign(int(x),int(y))
flipsign(x::Signed, y::Signed) = flipsign(promote(x,y)...)
flipsign(x::Signed, y::Float32) = flipsign(x, reinterpret(Int32,y))
flipsign(x::Signed, y::Float64) = flipsign(x, reinterpret(Int64,y))
Expand Down Expand Up @@ -100,9 +89,13 @@ for T in IntTypes
($)(x::$T, y::$T) = box($T,xor_int(unbox($T,x),unbox($T,y)))

<<(x::$T, y::Int32) = box($T, shl_int(unbox($T,x),unbox(Int32,y)))
>>(x::$T, y::Int32) = box($T,ashr_int(unbox($T,x),unbox(Int32,y)))
>>>(x::$T, y::Int32) = box($T,lshr_int(unbox($T,x),unbox(Int32,y)))
end
if issubtype(T,Unsigned)
@eval >>(x::$T, y::Int32) = box($T,lshr_int(unbox($T,x),unbox(Int32,y)))
else
@eval >>(x::$T, y::Int32) = box($T,ashr_int(unbox($T,x),unbox(Int32,y)))
end
end

bswap(x::Int8) = x
Expand All @@ -129,29 +122,15 @@ trailing_ones(x::Integer) = trailing_zeros(~x)

## integer comparisons ##

<(x::Int8, y::Int8) = slt_int(unbox(Int8,x),unbox(Int8,y))
<(x::Int16, y::Int16) = slt_int(unbox(Int16,x),unbox(Int16,y))
<(x::Int32, y::Int32) = slt_int(unbox(Int32,x),unbox(Int32,y))
<(x::Int64, y::Int64) = slt_int(unbox(Int64,x),unbox(Int64,y))
<(x::Int128, y::Int128) = slt_int(unbox(Int128,x),unbox(Int128,y))

<(x::Uint8, y::Uint8) = ult_int(unbox(Uint8,x),unbox(Uint8,y))
<(x::Uint16, y::Uint16) = ult_int(unbox(Uint16,x),unbox(Uint16,y))
<(x::Uint32, y::Uint32) = ult_int(unbox(Uint32,x),unbox(Uint32,y))
<(x::Uint64, y::Uint64) = ult_int(unbox(Uint64,x),unbox(Uint64,y))
<(x::Uint128, y::Uint128) = ult_int(unbox(Uint128,x),unbox(Uint128,y))

<=(x::Int8, y::Int8) = sle_int(unbox(Int8,x),unbox(Int8,y))
<=(x::Int16, y::Int16) = sle_int(unbox(Int16,x),unbox(Int16,y))
<=(x::Int32, y::Int32) = sle_int(unbox(Int32,x),unbox(Int32,y))
<=(x::Int64, y::Int64) = sle_int(unbox(Int64,x),unbox(Int64,y))
<=(x::Int128, y::Int128) = sle_int(unbox(Int128,x),unbox(Int128,y))

<=(x::Uint8, y::Uint8) = ule_int(unbox(Uint8,x),unbox(Uint8,y))
<=(x::Uint16, y::Uint16) = ule_int(unbox(Uint16,x),unbox(Uint16,y))
<=(x::Uint32, y::Uint32) = ule_int(unbox(Uint32,x),unbox(Uint32,y))
<=(x::Uint64, y::Uint64) = ule_int(unbox(Uint64,x),unbox(Uint64,y))
<=(x::Uint128, y::Uint128) = ule_int(unbox(Uint128,x),unbox(Uint128,y))
for T in IntTypes
if issubtype(T,Signed)
@eval <( x::$T, y::$T) = slt_int(unbox($T,x),unbox($T,y))
@eval <=(x::$T, y::$T) = sle_int(unbox($T,x),unbox($T,y))
else
@eval <( x::$T, y::$T) = ult_int(unbox($T,x),unbox($T,y))
@eval <=(x::$T, y::$T) = ule_int(unbox($T,x),unbox($T,y))
end
end

==(x::Signed, y::Unsigned) = (x >= 0) & (unsigned(x) == y)
==(x::Unsigned, y::Signed ) = (y >= 0) & (x == unsigned(y))
Expand All @@ -162,11 +141,8 @@ trailing_ones(x::Integer) = trailing_zeros(~x)

## integer conversions ##

const _inttypes = (Bool, Int8, Uint8, Int16, Uint16, Int32, Uint32, Char,
Int64, Uint64, Int128, Uint128)

for to in _inttypes, from in _inttypes
if !(to === from) && !(to === Bool)
for to in tuple(IntTypes...,Char), from in tuple(IntTypes...,Char,Bool)
if !(to === from)
if to.size < from.size
if issubtype(to, Signed)
@eval convert(::Type{$to}, x::($from)) = box($to,checked_trunc_sint($to,unbox($from,x)))
Expand Down Expand Up @@ -218,21 +194,18 @@ function convert(::Type{Uint128}, x::FloatingPoint)
end
convert(::Type{Uint128}, x::Float32) = convert(Uint128, float64(x))

convert(::Type{Char}, x::Float32) = char(convert(Int, x))
convert(::Type{Char}, x::Float64) = char(convert(Int, x))

convert(::Type{Signed}, x::Uint8 ) = convert(Int,x)
convert(::Type{Signed}, x::Uint16 ) = convert(Int,x)
convert(::Type{Signed}, x::Uint32 ) = convert(Int,x)
convert(::Type{Signed}, x::Uint8 ) = convert(Int8,x)
convert(::Type{Signed}, x::Uint16 ) = convert(Int16,x)
convert(::Type{Signed}, x::Uint32 ) = convert(Int32,x)
convert(::Type{Signed}, x::Uint64 ) = convert(Int64,x)
convert(::Type{Signed}, x::Uint128) = convert(Int128,x)
convert(::Type{Signed}, x::Float32) = convert(Int,x)
convert(::Type{Signed}, x::Float64) = convert(Int,x)
convert(::Type{Signed}, x::Char) = convert(Int,x)

convert(::Type{Unsigned}, x::Int8 ) = convert(Uint,x)
convert(::Type{Unsigned}, x::Int16 ) = convert(Uint,x)
convert(::Type{Unsigned}, x::Int32 ) = convert(Uint,x)
convert(::Type{Unsigned}, x::Int8 ) = convert(Uint8,x)
convert(::Type{Unsigned}, x::Int16 ) = convert(Uint16,x)
convert(::Type{Unsigned}, x::Int32 ) = convert(Uint32,x)
convert(::Type{Unsigned}, x::Int64 ) = convert(Uint64,x)
convert(::Type{Unsigned}, x::Int128 ) = convert(Uint128,x)
convert(::Type{Unsigned}, x::Float32) = convert(Uint,x)
Expand Down Expand Up @@ -372,12 +345,12 @@ typemax(::Type{Uint64}) = 0xffffffffffffffff
typemax(::Type{Int128} ) = $(int128((uint128(-1))>>int32(1)))
end

widen(::Type{Int8}) = Int
widen(::Type{Int16}) = Int
widen(::Type{Int8}) = Int16
widen(::Type{Int16}) = Int32
widen(::Type{Int32}) = Int64
widen(::Type{Int64}) = Int128
widen(::Type{Uint8}) = Uint
widen(::Type{Uint16}) = Uint
widen(::Type{Uint8}) = Uint16
widen(::Type{Uint16}) = Uint32
widen(::Type{Uint32}) = Uint64
widen(::Type{Uint64}) = Uint128

Expand Down Expand Up @@ -506,20 +479,18 @@ end

for T in (Int8,Uint8)
@eval function checked_mul(x::$T, y::$T)
xy = x*y
xy8 = convert($T,xy)
xy == xy8 || throw(OverflowError())
return xy8
xy = widemul(x,y)
(typemin($T) <= xy <= typemax($T)) || throw(OverflowError())
return itrunc($T,xy)
end
end

if WORD_SIZE == 32
for T in (Int64,Uint64)
@eval function checked_mul(x::$T, y::$T)
xy = int128(x)*int128(y)
xy64 = convert($T,xy)
xy == xy64 || throw(OverflowError())
return xy64
(typemin($T) <= xy <= typemax($T)) || throw(OverflowError())
return itrunc($T,xy)
end
end
else
Expand Down
14 changes: 7 additions & 7 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -104,17 +104,17 @@ rand(r::MersenneTwister) = dsfmt_genrand_close_open(r.state)
dsfmt_randui32() = dsfmt_gv_genrand_uint32()
dsfmt_randui64() = uint64(dsfmt_randui32()) | (uint64(dsfmt_randui32())<<32)

rand(::Type{Uint8}) = uint8(rand(Uint32))
rand(::Type{Uint16}) = uint16(rand(Uint32))
rand(::Type{Uint8}) = itrunc(Uint8,rand(Uint32))
rand(::Type{Uint16}) = itrunc(Uint16,rand(Uint32))
rand(::Type{Uint32}) = dsfmt_randui32()
rand(::Type{Uint64}) = dsfmt_randui64()
rand(::Type{Uint128}) = uint128(rand(Uint64))<<64 | rand(Uint64)

rand(::Type{Int8}) = int8(rand(Uint8))
rand(::Type{Int16}) = int16(rand(Uint16))
rand(::Type{Int32}) = int32(rand(Uint32))
rand(::Type{Int64}) = int64(rand(Uint64))
rand(::Type{Int128}) = int128(rand(Uint128))
rand(::Type{Int8}) = itrunc(Int8,rand(Uint32))
rand(::Type{Int16}) = itrunc(Int16,rand(Uint32))
rand(::Type{Int32}) = reinterpret(Int32,rand(Uint32))
rand(::Type{Int64}) = reinterpret(Int64,rand(Uint64))
rand(::Type{Int128}) = reinterpret(Int128,rand(Uint128))

# Arrays of random numbers

Expand Down
8 changes: 8 additions & 0 deletions base/reducedim.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ reducedim_init(f, op::OrFun, A::AbstractArray, region) = reducedim_initarray(A,

# specialize to make initialization more efficient for common cases

if Int === Int32
typealias SmallSigned Union(Int8,Int16)
typealias SmallUnsigned Union(Uint8,Uint16)
else
typealias SmallSigned Union(Int8,Int16,Int32)
typealias SmallUnsigned Union(Uint8,Uint16,Uint32)
end

typealias CommonReduceResult Union(Uint64,Uint128,Int64,Int128,Float32,Float64)

for (IT, RT) in ((CommonReduceResult, :(eltype(A))), (SmallSigned, :Int), (SmallUnsigned, :Uint))
Expand Down
8 changes: 4 additions & 4 deletions doc/stdlib/base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3090,9 +3090,9 @@ Mathematical Functions

Returns the nearest integral value of the same type as ``x`` not greater in magnitude than ``x``. ``digits`` and ``base`` work as above.

.. function:: iround(x) -> Integer
.. function:: iround([T,]x) -> Integer

Returns the nearest integer to ``x``.
Returns the nearest integer to ``x``, converted to an integer type, optionally passed as the first argument.

.. function:: iceil(x) -> Integer

Expand All @@ -3102,9 +3102,9 @@ Mathematical Functions

Returns the nearest integer not greater than ``x``.

.. function:: itrunc(x) -> Integer
.. function:: itrunc([T,]x) -> Integer

Returns the nearest integer not greater in magnitude than ``x``.
Returns the nearest integer not greater in magnitude than ``x``, converted to an integer type, optionally passed as the first argument.

.. function:: signif(x, digits, [base])

Expand Down
8 changes: 4 additions & 4 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,7 @@ end
@test -0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 ==
-(0b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001)

@test isa(-0x00,Uint)
@test isa(-0x00,Uint8)
@test isa(-0x0000000000000000,Uint64)
@test isa(-0x00000000000000000,Uint128)
@test isa(-0x00000000000000000000000000000000,Uint128)
Expand Down Expand Up @@ -1901,9 +1901,9 @@ end

for T = (Uint8,Int8,Uint16,Int16,Uint32,Int32,Uint64,Int64,Uint128,Int128)
for n = 1:2:1000
@test convert(T,n*(n^typemax(T))) == one(T)
@test n*(n^typemax(T)) & typemax(T) == 1
n = rand(T) | one(T)
@test convert(T,n*(n^typemax(T))) == one(T)
@test n*(n^typemax(T)) == 1
end
end

Expand Down Expand Up @@ -1931,7 +1931,7 @@ end
# widen
@test widen(1.5f0) === 1.5
@test widen(int32(42)) === int64(42)
@test widen(Int8) === Int
@test widen(Int8) === Int16
@test widen(Float32) === Float64
## Note: this should change to e.g. Float128 at some point
@test widen(Float64) === BigFloat
Expand Down

2 comments on commit 1d5050b

@StefanKarpinski
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the idea to simultaneously making IntN + IntN => IntN and making convert(IntN, x::IntM) check for overflow when N < M?

@JeffBezanson
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Though I suppose the first of those changes is much simpler and could be done separately.

Please sign in to comment.