From effff39b3ddf3bcd3ea3382206509acf24e3839c Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 16 Sep 2014 22:12:04 -0400 Subject: [PATCH 01/11] check integer truncation (#5413) and make more operators follow T+T => T (#3759) the sysimg builds, but still need to: - check same-size signed<->unsigned conversion - make tests pass --- base/Makefile | 4 +- base/dict.jl | 2 +- base/int.jl | 207 +++++++++++-------------------------------------- base/string.jl | 2 +- 4 files changed, 51 insertions(+), 164 deletions(-) diff --git a/base/Makefile b/base/Makefile index af4c87b8f52e5..f6a9fabbe6e38 100644 --- a/base/Makefile +++ b/base/Makefile @@ -16,9 +16,9 @@ all: pcre_h.jl errno_h.jl build_h.jl.phony fenv_constants.jl file_constants.jl u pcre_h.jl: ifeq ($(USE_SYSTEM_PCRE), 1) - @$(call PRINT_PERL, $(CPP) -dM $(shell $(PCRE_CONFIG) --prefix)/include/pcre.h | perl -nle '/^\s*#define\s+PCRE_(\w*)\s*\(?($(PCRE_CONST))\)?\s*$$/ and print "const $$1 = uint32($$2)"' | sort > $@) + @$(call PRINT_PERL, $(CPP) -dM $(shell $(PCRE_CONFIG) --prefix)/include/pcre.h | perl -nle '/^\s*#define\s+PCRE_(\w*)\s*\(?($(PCRE_CONST))\)?\s*$$/ and print "const $$1 = int32($$2)"' | sort > $@) else - @$(call PRINT_PERL, $(CPP) -dM $(build_includedir)/pcre.h | perl -nle '/^\s*#define\s+PCRE_(\w*)\s*\(?($(PCRE_CONST))\)?\s*$$/ and print "const $$1 = uint32($$2)"' | sort > $@) + @$(call PRINT_PERL, $(CPP) -dM $(build_includedir)/pcre.h | perl -nle '/^\s*#define\s+PCRE_(\w*)\s*\(?($(PCRE_CONST))\)?\s*$$/ and print "const $$1 = int32($$2)"' | sort > $@) endif errno_h.jl: diff --git a/base/dict.jl b/base/dict.jl index 9fb66ab195748..44008c39f6962 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -385,7 +385,7 @@ function deserialize{K,V}(s, T::Type{Dict{K,V}}) return t end -hashindex(key, sz) = (int(hash(key)) & (sz-1)) + 1 +hashindex(key, sz) = (reinterpret(Int,hash(key)) & (sz-1)) + 1 isslotempty(h::Dict, i::Int) = h.slots[i] == 0x0 isslotfilled(h::Dict, i::Int) = h.slots[i] == 0x1 diff --git a/base/int.jl b/base/int.jl index fa3d5f81b1875..bed14be303d9e 100644 --- a/base/int.jl +++ b/base/int.jl @@ -10,42 +10,20 @@ end ## integer arithmetic ## --(x::SmallSigned) = -int(x) --(x::SmallUnsigned) = -uint(x) - -+{T<:SmallSigned}(x::T, y::T) = int(x) + int(y) --{T<:SmallSigned}(x::T, y::T) = int(x) - int(y) -*{T<:SmallSigned}(x::T, y::T) = int(x) * int(y) - -+{T<:SmallUnsigned}(x::T, y::T) = uint(x) + uint(y) --{T<:SmallUnsigned}(x::T, y::T) = uint(x) - uint(y) -*{T<:SmallUnsigned}(x::T, y::T) = uint(x) * uint(y) - --(x::Int) = box(Int,neg_int(unbox(Int,x))) --(x::Uint) = box(Uint,neg_int(unbox(Uint,x))) --(x::Int64) = box(Int64,neg_int(unbox(Int64,x))) --(x::Uint64) = box(Uint64,neg_int(unbox(Uint64,x))) --(x::Int128) = box(Int128,neg_int(unbox(Int128,x))) --(x::Uint128) = box(Uint128,neg_int(unbox(Uint128,x))) - -+(x::Int, y::Int) = box(Int,add_int(unbox(Int,x),unbox(Int,y))) -+(x::Uint, y::Uint) = box(Uint,add_int(unbox(Uint,x),unbox(Uint,y))) -+(x::Int64, y::Int64) = box(Int64,add_int(unbox(Int64,x),unbox(Int64,y))) -+(x::Uint64, y::Uint64) = box(Uint64,add_int(unbox(Uint64,x),unbox(Uint64,y))) -+(x::Int128, y::Int128) = box(Int128,add_int(unbox(Int128,x),unbox(Int128,y))) -+(x::Uint128, y::Uint128) = box(Uint128,add_int(unbox(Uint128,x),unbox(Uint128,y))) - --(x::Int, y::Int) = box(Int,sub_int(unbox(Int,x),unbox(Int,y))) --(x::Uint, y::Uint) = box(Uint,sub_int(unbox(Uint,x),unbox(Uint,y))) --(x::Int64, y::Int64) = box(Int64,sub_int(unbox(Int64,x),unbox(Int64,y))) --(x::Uint64, y::Uint64) = box(Uint64,sub_int(unbox(Uint64,x),unbox(Uint64,y))) --(x::Int128, y::Int128) = box(Int128,sub_int(unbox(Int128,x),unbox(Int128,y))) --(x::Uint128, y::Uint128) = box(Uint128,sub_int(unbox(Uint128,x),unbox(Uint128,y))) - -*(x::Int, y::Int) = box(Int,mul_int(unbox(Int,x),unbox(Int,y))) -*(x::Uint, y::Uint) = box(Uint,mul_int(unbox(Uint,x),unbox(Uint,y))) -*(x::Int64, y::Int64) = box(Int64,mul_int(unbox(Int64,x),unbox(Int64,y))) -*(x::Uint64, y::Uint64) = box(Uint64,mul_int(unbox(Uint64,x),unbox(Uint64,y))) +const IntTypes = (Int8, Uint8, Int16, Uint16, Int32, Uint32, + Int64, Uint64, Int128, Uint128) + ++(x::Int, y::Int) = box(Int,add_int(unbox(Int,x),unbox(Int,y))) +<(x::Int, y::Int) = slt_int(unbox(Int,x),unbox(Int,y)) + +for T in IntTypes + @eval begin + -(x::$T) = box($T,neg_int(unbox($T,x))) + +(x::$T, y::$T) = box($T, add_int(unbox($T,x),unbox($T,y))) + -(x::$T, y::$T) = box($T, sub_int(unbox($T,x),unbox($T,y))) + *(x::$T, y::$T) = box($T, mul_int(unbox($T,x),unbox($T,y))) + end +end /(x::Integer, y::Integer) = float(x)/float(y) inv(x::Integer) = float(one(x))/float(x) @@ -113,89 +91,19 @@ cld{T<:Integer }(x::T, y::T) = div(x,y)+(!signbit(x$y)&(rem(x,y)!=0)) ## integer bitwise operations ## -~(x::Int8 ) = box(Int8,not_int(unbox(Int8,x))) -~(x::Int16) = box(Int16,not_int(unbox(Int16,x))) -~(x::Int32) = box(Int32,not_int(unbox(Int32,x))) -~(x::Int64) = box(Int64,not_int(unbox(Int64,x))) -~(x::Int128) = box(Int128,not_int(unbox(Int128,x))) - -~(x::Uint8 ) = box(Uint8,not_int(unbox(Uint8,x))) -~(x::Uint16) = box(Uint16,not_int(unbox(Uint16,x))) -~(x::Uint32) = box(Uint32,not_int(unbox(Uint32,x))) -~(x::Uint64) = box(Uint64,not_int(unbox(Uint64,x))) -~(x::Uint128) = box(Uint128,not_int(unbox(Uint128,x))) - -(&)(x::Int8, y::Int8 ) = box(Int8,and_int(unbox(Int8,x),unbox(Int8,y))) -(&)(x::Int16, y::Int16) = box(Int16,and_int(unbox(Int16,x),unbox(Int16,y))) -(&)(x::Int32, y::Int32) = box(Int32,and_int(unbox(Int32,x),unbox(Int32,y))) -(&)(x::Int64, y::Int64) = box(Int64,and_int(unbox(Int64,x),unbox(Int64,y))) -(&)(x::Int128, y::Int128) = box(Int128,and_int(unbox(Int128,x),unbox(Int128,y))) - -(&)(x::Uint8, y::Uint8 ) = box(Uint8,and_int(unbox(Uint8,x),unbox(Uint8,y))) -(&)(x::Uint16, y::Uint16) = box(Uint16,and_int(unbox(Uint16,x),unbox(Uint16,y))) -(&)(x::Uint32, y::Uint32) = box(Uint32,and_int(unbox(Uint32,x),unbox(Uint32,y))) -(&)(x::Uint64, y::Uint64) = box(Uint64,and_int(unbox(Uint64,x),unbox(Uint64,y))) -(&)(x::Uint128, y::Uint128) = box(Uint128,and_int(unbox(Uint128,x),unbox(Uint128,y))) - -|(x::Int8, y::Int8) = box(Int8,or_int(unbox(Int8,x),unbox(Int8,y))) -|(x::Int16, y::Int16) = box(Int16,or_int(unbox(Int16,x),unbox(Int16,y))) -|(x::Int32, y::Int32) = box(Int32,or_int(unbox(Int32,x),unbox(Int32,y))) -|(x::Int64, y::Int64) = box(Int64,or_int(unbox(Int64,x),unbox(Int64,y))) -|(x::Int128, y::Int128) = box(Int128,or_int(unbox(Int128,x),unbox(Int128,y))) - -|(x::Uint8, y::Uint8) = box(Uint8,or_int(unbox(Uint8,x),unbox(Uint8,y))) -|(x::Uint16, y::Uint16) = box(Uint16,or_int(unbox(Uint16,x),unbox(Uint16,y))) -|(x::Uint32, y::Uint32) = box(Uint32,or_int(unbox(Uint32,x),unbox(Uint32,y))) -|(x::Uint64, y::Uint64) = box(Uint64,or_int(unbox(Uint64,x),unbox(Uint64,y))) -|(x::Uint128, y::Uint128) = box(Uint128,or_int(unbox(Uint128,x),unbox(Uint128,y))) - -($)(x::Int8, y::Int8) = box(Int8,xor_int(unbox(Int8,x),unbox(Int8,y))) -($)(x::Int16, y::Int16) = box(Int16,xor_int(unbox(Int16,x),unbox(Int16,y))) -($)(x::Int32, y::Int32) = box(Int32,xor_int(unbox(Int32,x),unbox(Int32,y))) -($)(x::Int64, y::Int64) = box(Int64,xor_int(unbox(Int64,x),unbox(Int64,y))) -($)(x::Int128, y::Int128) = box(Int128,xor_int(unbox(Int128,x),unbox(Int128,y))) - -($)(x::Uint8, y::Uint8) = box(Uint8,xor_int(unbox(Uint8,x),unbox(Uint8,y))) -($)(x::Uint16, y::Uint16) = box(Uint16,xor_int(unbox(Uint16,x),unbox(Uint16,y))) -($)(x::Uint32, y::Uint32) = box(Uint32,xor_int(unbox(Uint32,x),unbox(Uint32,y))) -($)(x::Uint64, y::Uint64) = box(Uint64,xor_int(unbox(Uint64,x),unbox(Uint64,y))) -($)(x::Uint128, y::Uint128) = box(Uint128,xor_int(unbox(Uint128,x),unbox(Uint128,y))) - -<<(x::Int8, y::Int32) = box(Int8,shl_int(unbox(Int8,x),unbox(Int32,y))) -<<(x::Int16, y::Int32) = box(Int16,shl_int(unbox(Int16,x),unbox(Int32,y))) -<<(x::Int32, y::Int32) = box(Int32,shl_int(unbox(Int32,x),unbox(Int32,y))) -<<(x::Int64, y::Int32) = box(Int64,shl_int(unbox(Int64,x),unbox(Int32,y))) -<<(x::Int128, y::Int32) = box(Int128,shl_int(unbox(Int128,x),unbox(Int32,y))) - -<<(x::Uint8, y::Int32) = box(Uint8,shl_int(unbox(Uint8,x),unbox(Int32,y))) -<<(x::Uint16, y::Int32) = box(Uint16,shl_int(unbox(Uint16,x),unbox(Int32,y))) -<<(x::Uint32, y::Int32) = box(Uint32,shl_int(unbox(Int32,x),unbox(Uint32,y))) -<<(x::Uint64, y::Int32) = box(Uint64,shl_int(unbox(Uint64,x),unbox(Int32,y))) -<<(x::Uint128, y::Int32) = box(Uint128,shl_int(unbox(Uint128,x),unbox(Int32,y))) - ->>(x::Int8, y::Int32) = box(Int8,ashr_int(unbox(Int8,x),unbox(Int32,y))) ->>(x::Int16, y::Int32) = box(Int16,ashr_int(unbox(Int16,x),unbox(Int32,y))) ->>(x::Int32, y::Int32) = box(Int32,ashr_int(unbox(Int32,x),unbox(Int32,y))) ->>(x::Int64, y::Int32) = box(Int64,ashr_int(unbox(Int64,x),unbox(Int32,y))) ->>(x::Int128, y::Int32) = box(Int128,ashr_int(unbox(Int128,x),unbox(Int32,y))) - ->>(x::Uint8, y::Int32) = box(Uint8,lshr_int(unbox(Uint8,x),unbox(Int32,y))) ->>(x::Uint16, y::Int32) = box(Uint16,lshr_int(unbox(Uint16,x),unbox(Int32,y))) ->>(x::Uint32, y::Int32) = box(Uint32,lshr_int(unbox(Int32,x),unbox(Uint32,y))) ->>(x::Uint64, y::Int32) = box(Uint64,lshr_int(unbox(Uint64,x),unbox(Int32,y))) ->>(x::Uint128, y::Int32) = box(Uint128,lshr_int(unbox(Uint128,x),unbox(Int32,y))) - ->>>(x::Int8, y::Int32) = box(Int8,lshr_int(unbox(Int8,x),unbox(Int32,y))) ->>>(x::Int16, y::Int32) = box(Int16,lshr_int(unbox(Int16,x),unbox(Int32,y))) ->>>(x::Int32, y::Int32) = box(Int32,lshr_int(unbox(Int32,x),unbox(Int32,y))) ->>>(x::Int64, y::Int32) = box(Int64,lshr_int(unbox(Int64,x),unbox(Int32,y))) ->>>(x::Int128, y::Int32) = box(Int128,lshr_int(unbox(Int128,x),unbox(Int32,y))) - ->>>(x::Uint8, y::Int32) = box(Uint8,lshr_int(unbox(Uint8,x),unbox(Int32,y))) ->>>(x::Uint16, y::Int32) = box(Uint16,lshr_int(unbox(Uint16,x),unbox(Int32,y))) ->>>(x::Uint32, y::Int32) = box(Uint32,lshr_int(unbox(Int32,x),unbox(Uint32,y))) ->>>(x::Uint64, y::Int32) = box(Uint64,lshr_int(unbox(Uint64,x),unbox(Int32,y))) ->>>(x::Uint128, y::Int32) = box(Uint128,lshr_int(unbox(Uint128,x),unbox(Int32,y))) +for T in IntTypes + @eval begin + ~(x::$T) = box($T,not_int(unbox($T,x))) + + (&)(x::$T, y::$T) = box($T,and_int(unbox($T,x),unbox($T,y))) + (|)(x::$T, y::$T) = box($T, or_int(unbox($T,x),unbox($T,y))) + ($)(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 +end bswap(x::Int8) = x bswap(x::Uint8) = x @@ -208,39 +116,13 @@ bswap(x::Uint64) = box(Uint64,bswap_int(unbox(Uint64,x))) bswap(x::Int128) = box(Int128,bswap_int(unbox(Int128,x))) bswap(x::Uint128) = box(Uint128,bswap_int(unbox(Uint128,x))) -count_ones(x::Int8) = int(box(Int8,ctpop_int(unbox(Int8,x)))) -count_ones(x::Uint8) = int(box(Uint8,ctpop_int(unbox(Uint8,x)))) -count_ones(x::Int16) = int(box(Int16,ctpop_int(unbox(Int16,x)))) -count_ones(x::Uint16) = int(box(Uint16,ctpop_int(unbox(Uint16,x)))) -count_ones(x::Int32) = int(box(Int32,ctpop_int(unbox(Int32,x)))) -count_ones(x::Uint32) = int(box(Uint32,ctpop_int(unbox(Uint32,x)))) -count_ones(x::Int64) = int(box(Int64,ctpop_int(unbox(Int64,x)))) -count_ones(x::Uint64) = int(box(Uint64,ctpop_int(unbox(Uint64,x)))) -count_ones(x::Int128) = int(box(Int128,ctpop_int(unbox(Int128,x)))) -count_ones(x::Uint128) = int(box(Uint128,ctpop_int(unbox(Uint128,x)))) - -leading_zeros(x::Int8) = int(box(Int8,ctlz_int(unbox(Int8,x)))) -leading_zeros(x::Uint8) = int(box(Uint8,ctlz_int(unbox(Uint8,x)))) -leading_zeros(x::Int16) = int(box(Int16,ctlz_int(unbox(Int16,x)))) -leading_zeros(x::Uint16) = int(box(Uint16,ctlz_int(unbox(Uint16,x)))) -leading_zeros(x::Int32) = int(box(Int32,ctlz_int(unbox(Int32,x)))) -leading_zeros(x::Uint32) = int(box(Uint32,ctlz_int(unbox(Uint32,x)))) -leading_zeros(x::Int64) = int(box(Int64,ctlz_int(unbox(Int64,x)))) -leading_zeros(x::Uint64) = int(box(Uint64,ctlz_int(unbox(Uint64,x)))) -leading_zeros(x::Int128) = int(box(Int128,ctlz_int(unbox(Int128,x)))) -leading_zeros(x::Uint128) = int(box(Uint128,ctlz_int(unbox(Uint128,x)))) - -trailing_zeros(x::Int8) = int(box(Int8,cttz_int(unbox(Int8,x)))) -trailing_zeros(x::Uint8) = int(box(Uint8,cttz_int(unbox(Uint8,x)))) -trailing_zeros(x::Int16) = int(box(Int16,cttz_int(unbox(Int16,x)))) -trailing_zeros(x::Uint16) = int(box(Uint16,cttz_int(unbox(Uint16,x)))) -trailing_zeros(x::Int32) = int(box(Int32,cttz_int(unbox(Int32,x)))) -trailing_zeros(x::Uint32) = int(box(Uint32,cttz_int(unbox(Uint32,x)))) -trailing_zeros(x::Int64) = int(box(Int64,cttz_int(unbox(Int64,x)))) -trailing_zeros(x::Uint64) = int(box(Uint64,cttz_int(unbox(Uint64,x)))) -trailing_zeros(x::Int128) = int(box(Int128,cttz_int(unbox(Int128,x)))) -trailing_zeros(x::Uint128) = int(box(Uint128,cttz_int(unbox(Uint128,x)))) - +for T in IntTypes + @eval begin + count_ones(x::$T) = int(box($T,ctpop_int(unbox($T,x)))) + leading_zeros(x::$T) = int(box($T,ctlz_int(unbox($T,x)))) + trailing_zeros(x::$T) = int(box($T,cttz_int(unbox($T,x)))) + end +end count_zeros (x::Integer) = count_ones(~x) leading_ones (x::Integer) = leading_zeros(~x) trailing_ones(x::Integer) = trailing_zeros(~x) @@ -284,9 +166,14 @@ 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) + if !(to === from) && !(to === Bool) if to.size < from.size - @eval convert(::Type{$to}, x::($from)) = box($to,trunc_int($to,unbox($from,x))) + if issubtype(to, Signed) + @eval convert(::Type{$to}, x::($from)) = box($to,checked_trunc_sint($to,unbox($from,x))) + else + @eval convert(::Type{$to}, x::($from)) = box($to,checked_trunc_uint($to,unbox($from,x))) + end + @eval itrunc(::Type{$to}, x::($from)) = box($to,trunc_int($to,unbox($from,x))) elseif from.size < to.size || from===Bool if issubtype(from, Signed) @eval convert(::Type{$to}, x::($from)) = box($to,sext_int($to,unbox($from,x))) @@ -402,9 +289,9 @@ const WORD_SIZE = int(Int.size)*8 ## integer promotions ## -promote_rule(::Type{Int16}, ::Type{Int8} ) = Int -promote_rule(::Type{Int32}, ::Type{Int8} ) = Int -promote_rule(::Type{Int32}, ::Type{Int16}) = Int +promote_rule(::Type{Int16}, ::Type{Int8} ) = Int16 +promote_rule(::Type{Int32}, ::Type{Int8} ) = Int32 +promote_rule(::Type{Int32}, ::Type{Int16}) = Int32 promote_rule(::Type{Int64}, ::Type{Int8} ) = Int64 promote_rule(::Type{Int64}, ::Type{Int16}) = Int64 promote_rule(::Type{Int64}, ::Type{Int32}) = Int64 @@ -413,9 +300,9 @@ promote_rule(::Type{Int128}, ::Type{Int16}) = Int128 promote_rule(::Type{Int128}, ::Type{Int32}) = Int128 promote_rule(::Type{Int128}, ::Type{Int64}) = Int128 -promote_rule(::Type{Uint16}, ::Type{Uint8} ) = Uint -promote_rule(::Type{Uint32}, ::Type{Uint8} ) = Uint -promote_rule(::Type{Uint32}, ::Type{Uint16}) = Uint +promote_rule(::Type{Uint16}, ::Type{Uint8} ) = Uint16 +promote_rule(::Type{Uint32}, ::Type{Uint8} ) = Uint32 +promote_rule(::Type{Uint32}, ::Type{Uint16}) = Uint32 promote_rule(::Type{Uint64}, ::Type{Uint8} ) = Uint64 promote_rule(::Type{Uint64}, ::Type{Uint16}) = Uint64 promote_rule(::Type{Uint64}, ::Type{Uint32}) = Uint64 diff --git a/base/string.jl b/base/string.jl index b9a3f09c93285..2d169ebf86d90 100644 --- a/base/string.jl +++ b/base/string.jl @@ -660,7 +660,7 @@ const memhash = Uint == Uint64 ? :memhash_seed : :memhash32_seed function hash{T<:ByteString}(s::Union(T,SubString{T}), h::Uint) h += uint(0x71e729fd56419c81) - ccall(memhash, Uint, (Ptr{Uint8}, Csize_t, Uint32), s, sizeof(s), h) + h + ccall(memhash, Uint, (Ptr{Uint8}, Csize_t, Uint32), s, sizeof(s), itrunc(Uint32,h)) + h end hash(s::String, h::Uint) = hash(bytestring(s), h) From 1d5050bb89566d794fc961c7207fabcbe9a8864b Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 17 Sep 2014 15:02:39 -0400 Subject: [PATCH 02/11] get numbers test passing with checked integer conversions and type-stable arithmetic --- base/char.jl | 4 ++ base/float.jl | 10 ++--- base/int.jl | 97 ++++++++++++++++----------------------------- base/random.jl | 14 +++---- base/reducedim.jl | 8 ++++ doc/stdlib/base.rst | 8 ++-- test/numbers.jl | 8 ++-- 7 files changed, 66 insertions(+), 83 deletions(-) diff --git a/base/char.jl b/base/char.jl index 7a094dec85ce2..05cb6124e1c70 100644 --- a/base/char.jl +++ b/base/char.jl @@ -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 diff --git a/base/float.jl b/base/float.jl index a43243daf9f08..a4cba309e8c41 100644 --- a/base/float.jl +++ b/base/float.jl @@ -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 diff --git a/base/int.jl b/base/int.jl index bed14be303d9e..a4167ad1a9632 100644 --- a/base/int.jl +++ b/base/int.jl @@ -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, @@ -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)) @@ -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 @@ -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)) @@ -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))) @@ -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) @@ -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 @@ -506,10 +479,9 @@ 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 @@ -517,9 +489,8 @@ 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 diff --git a/base/random.jl b/base/random.jl index 789015dfe4e23..68f69fb834037 100644 --- a/base/random.jl +++ b/base/random.jl @@ -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 diff --git a/base/reducedim.jl b/base/reducedim.jl index 23b0950298174..23d65ab898c47 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -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)) diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index bfc2ca46c3e65..d4f615077c5c1 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -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 @@ -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]) diff --git a/test/numbers.jl b/test/numbers.jl index 6e8b9408f27fc..0c6473cd3a747 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -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) @@ -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 @@ -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 From 8495944ef03f73d1b7edf690cbc7efe79d902649 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Wed, 17 Sep 2014 16:39:20 -0400 Subject: [PATCH 03/11] make a couple things safe for checked signed<->unsigned conversion --- base/int.jl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/base/int.jl b/base/int.jl index a4167ad1a9632..69cb22a4f875c 100644 --- a/base/int.jl +++ b/base/int.jl @@ -132,12 +132,14 @@ for T in IntTypes end end -==(x::Signed, y::Unsigned) = (x >= 0) & (unsigned(x) == y) -==(x::Unsigned, y::Signed ) = (y >= 0) & (x == unsigned(y)) -< (x::Signed, y::Unsigned) = (x < 0) | (unsigned(x) < y) -< (x::Unsigned, y::Signed ) = (y > 0) & (x < unsigned(y)) -<=(x::Signed, y::Unsigned) = (x <= 0) | (unsigned(x) <= y) -<=(x::Unsigned, y::Signed ) = (y >= 0) & (x <= unsigned(y)) +asunsigned(x) = reinterpret(typeof(unsigned(zero(x))), x) + +==(x::Signed, y::Unsigned) = (x >= 0) & (asunsigned(x) == y) +==(x::Unsigned, y::Signed ) = (y >= 0) & (x == asunsigned(y)) +< (x::Signed, y::Unsigned) = (x < 0) | (asunsigned(x) < y) +< (x::Unsigned, y::Signed ) = (y > 0) & (x < asunsigned(y)) +<=(x::Signed, y::Unsigned) = (x <= 0) | (asunsigned(x) <= y) +<=(x::Unsigned, y::Signed ) = (y >= 0) & (x <= asunsigned(y)) ## integer conversions ## @@ -338,12 +340,10 @@ typemin(::Type{Int64 }) = -9223372036854775808 typemax(::Type{Int64 }) = 9223372036854775807 typemin(::Type{Uint64}) = uint64(0) typemax(::Type{Uint64}) = 0xffffffffffffffff -@eval begin - typemin(::Type{Uint128}) = uint128(0) - typemax(::Type{Uint128}) = $(uint128(-1)) - typemin(::Type{Int128} ) = $(int128((uint128(-1))>>int32(1))+int128(1)) - typemax(::Type{Int128} ) = $(int128((uint128(-1))>>int32(1))) -end +@eval typemin(::Type{Uint128}) = $(uint128(0)) +@eval typemax(::Type{Uint128}) = $(box(Uint128,unbox(Int128,convert(Int128,-1)))) +@eval typemin(::Type{Int128} ) = $(convert(Int128,1)<>int32(1)))) widen(::Type{Int8}) = Int16 widen(::Type{Int16}) = Int32 From e1690fce86701d24614cc999ec49c34f5531f698 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 18 Sep 2014 18:45:23 -0400 Subject: [PATCH 04/11] check signed<->unsigned conversions this would be a bit cleaner without the code in intfuncs that dispatches on Unsigned. signed() and unsigned() are convenient for testing bit patterns in the test suite. for now replace with assigned() and asunsigned(). uint8(x) is convenient for moving bytes around, so it remains unchecked. we should perhaps rename this to byte(), and either eliminate uint8() entirely, or make it checked. --- base/boot.jl | 2 +- base/dict.jl | 2 +- base/int.jl | 19 +++++--- base/intfuncs.jl | 18 ++++---- base/number.jl | 4 +- src/intrinsics.cpp | 13 +++++- test/core.jl | 18 ++++---- test/numbers.jl | 112 +++++++++++++++++++++++---------------------- 8 files changed, 104 insertions(+), 84 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index d054fad583e06..e34d15354e379 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -151,7 +151,7 @@ export #ccall, cglobal, llvmcall, abs_float, add_float, add_int, and_int, ashr_int, #box, bswap_int, checked_fptosi, checked_fptoui, checked_sadd, #checked_smul, checked_ssub, checked_uadd, checked_umul, checked_usub, - #checked_trunc_sint, checked_trunc_uint, + #checked_trunc_sint, checked_trunc_uint, check_top_bit, #nan_dom_err, copysign_float, ctlz_int, ctpop_int, cttz_int, #div_float, eq_float, eq_int, eqfsi64, eqfui64, flipsign_int, select_value, #sqrt_llvm, powi_llvm, diff --git a/base/dict.jl b/base/dict.jl index 44008c39f6962..5381a97770d6c 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -288,7 +288,7 @@ end empty!(t::ObjectIdDict) = (t.ht = cell(length(t.ht)); t) -_oidd_nextind(a, i) = int(ccall(:jl_eqtable_nextind, Csize_t, (Any, Csize_t), a, i)) +_oidd_nextind(a, i) = reinterpret(Int,ccall(:jl_eqtable_nextind, Csize_t, (Any, Csize_t), a, i)) start(t::ObjectIdDict) = _oidd_nextind(t.ht, 0) done(t::ObjectIdDict, i) = (i == -1) diff --git a/base/int.jl b/base/int.jl index 69cb22a4f875c..85760b852cd2d 100644 --- a/base/int.jl +++ b/base/int.jl @@ -43,17 +43,17 @@ abs(x::Signed) = flipsign(x,x) ~(n::Integer) = -n-1 -div(x::Signed, y::Unsigned) = flipsign(signed(div(unsigned(abs(x)),y)),x) -div(x::Unsigned, y::Signed) = unsigned(flipsign(signed(div(x,unsigned(abs(y)))),y)) +div(x::Signed, y::Unsigned) = flipsign(assigned(div(asunsigned(abs(x)),y)),x) +div(x::Unsigned, y::Signed) = asunsigned(flipsign(assigned(div(x,asunsigned(abs(y)))),y)) -rem(x::Signed, y::Unsigned) = flipsign(signed(rem(unsigned(abs(x)),y)),x) -rem(x::Unsigned, y::Signed) = rem(x,unsigned(abs(y))) +rem(x::Signed, y::Unsigned) = flipsign(assigned(rem(asunsigned(abs(x)),y)),x) +rem(x::Unsigned, y::Signed) = rem(x,asunsigned(abs(y))) fld(x::Signed, y::Unsigned) = div(x,y)-(signbit(x)&(rem(x,y)!=0)) fld(x::Unsigned, y::Signed) = div(x,y)-(signbit(y)&(rem(x,y)!=0)) -mod(x::Signed, y::Unsigned) = rem(y+unsigned(rem(x,y)),y) -mod(x::Unsigned, y::Signed) = rem(y+signed(rem(x,y)),y) +mod(x::Signed, y::Unsigned) = rem(y+asunsigned(rem(x,y)),y) +mod(x::Unsigned, y::Signed) = rem(y+assigned(rem(x,y)),y) cld(x::Signed, y::Unsigned) = div(x,y)+(!signbit(x)&(rem(x,y)!=0)) cld(x::Unsigned, y::Signed) = div(x,y)+(!signbit(y)&(rem(x,y)!=0)) @@ -133,6 +133,7 @@ for T in IntTypes end asunsigned(x) = reinterpret(typeof(unsigned(zero(x))), x) +assigned(x) = reinterpret(typeof(signed(zero(x))), x) ==(x::Signed, y::Unsigned) = (x >= 0) & (asunsigned(x) == y) ==(x::Unsigned, y::Signed ) = (y >= 0) & (x == asunsigned(y)) @@ -158,6 +159,9 @@ for to in tuple(IntTypes...,Char), from in tuple(IntTypes...,Char,Bool) else @eval convert(::Type{$to}, x::($from)) = box($to,zext_int($to,unbox($from,x))) end + elseif !(issubtype(from,Signed) === issubtype(to,Signed)) + # raise InexactError if x's top bit is set + @eval convert(::Type{$to}, x::($from)) = box($to,check_top_bit(unbox($from,x))) else @eval convert(::Type{$to}, x::($from)) = box($to,unbox($from,x)) end @@ -223,7 +227,8 @@ int32(x) = convert(Int32,x) int64(x) = convert(Int64,x) int128(x) = convert(Int128,x) -uint8(x) = convert(Uint8,x) +uint8(x) = itrunc(Uint8,x) +uint8(x::Int8) = box(Uint8,unbox(Int8,x)) uint16(x) = convert(Uint16,x) uint32(x) = convert(Uint32,x) uint64(x) = convert(Uint64,x) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 077b363eed90b..37592d98fecec 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -109,10 +109,10 @@ end # smallest power of 2 >= x nextpow2(x::Unsigned) = one(x)<<((sizeof(x)<<3)-leading_zeros(x-1)) -nextpow2(x::Integer) = oftype(x,x < 0 ? -nextpow2(unsigned(-x)) : nextpow2(unsigned(x))) +nextpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -nextpow2(unsigned(-x)) : nextpow2(unsigned(x))) prevpow2(x::Unsigned) = (one(x)>>(x==0)) << ((sizeof(x)<<3)-leading_zeros(x)-1) -prevpow2(x::Integer) = oftype(x,x < 0 ? -prevpow2(unsigned(-x)) : prevpow2(unsigned(x))) +prevpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -prevpow2(unsigned(-x)) : prevpow2(unsigned(x))) ispow2(x::Integer) = count_ones(x)==1 @@ -154,7 +154,7 @@ function ndigits0z(x::Uint128) end return n + ndigits0z(uint64(x)) end -ndigits0z(x::Integer) = ndigits0z(unsigned(abs(x))) +ndigits0z(x::Integer) = ndigits0z(asunsigned(abs(x))) const ndigits_max_mul = WORD_SIZE==32 ? 69000000 : 290000000000000000 @@ -175,13 +175,13 @@ function ndigits0z(n::Unsigned, b::Int) end return d end -ndigits0z(x::Integer, b::Integer) = ndigits0z(unsigned(abs(x)),int(b)) +ndigits0z(x::Integer, b::Integer) = ndigits0z(asunsigned(abs(x)),int(b)) ndigits(x::Unsigned, b::Integer) = x==0 ? 1 : ndigits0z(x,int(b)) ndigits(x::Unsigned) = x==0 ? 1 : ndigits0z(x) -ndigits(x::Integer, b::Integer) = ndigits(unsigned(abs(x)),int(b)) -ndigits(x::Integer) = ndigits(unsigned(abs(x))) +ndigits(x::Integer, b::Integer) = ndigits(asunsigned(abs(x)),int(b)) +ndigits(x::Integer) = ndigits(asunsigned(abs(x))) ## integer to string functions ## @@ -252,7 +252,7 @@ function base(b::Int, x::Unsigned, pad::Int, neg::Bool) if neg; a[1]='-'; end ASCIIString(a) end -base(b::Integer, n::Integer, pad::Integer=1) = base(int(b), unsigned(abs(n)), pad, n<0) +base(b::Integer, n::Integer, pad::Integer=1) = base(int(b), asunsigned(abs(n)), pad, n<0) for sym in (:bin, :oct, :dec, :hex) @eval begin @@ -260,8 +260,8 @@ for sym in (:bin, :oct, :dec, :hex) ($sym)(x::Unsigned) = ($sym)(x,1,false) ($sym)(x::Char, p::Int) = ($sym)(unsigned(x),p,false) ($sym)(x::Char) = ($sym)(unsigned(x),1,false) - ($sym)(x::Integer, p::Int) = ($sym)(unsigned(abs(x)),p,x<0) - ($sym)(x::Integer) = ($sym)(unsigned(abs(x)),1,x<0) + ($sym)(x::Integer, p::Int) = ($sym)(asunsigned(abs(x)),p,x<0) + ($sym)(x::Integer) = ($sym)(asunsigned(abs(x)),1,x<0) end end diff --git a/base/number.jl b/base/number.jl index a0b641346e040..350418e75da18 100644 --- a/base/number.jl +++ b/base/number.jl @@ -39,11 +39,11 @@ done(x::Number, state) = state isempty(x::Number) = false in(x::Number, y::Number) = x == y -function reinterpret{T}(::Type{T}, x) +function reinterpret{T,S}(::Type{T}, x::S) if !isbits(T) error("cannot reinterpret to type ", T) end - box(T,x) + box(T,unbox(S,x)) end map(f::Callable, x::Number) = f(x) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 1a6a4518adf01..8f0b0b22b25c9 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -28,7 +28,7 @@ namespace JL_I { fptrunc, fpext, // checked conversion fpsiround, fpuiround, checked_fptosi, checked_fptoui, - checked_trunc_sint, checked_trunc_uint, + checked_trunc_sint, checked_trunc_uint, check_top_bit, // checked arithmetic checked_sadd, checked_uadd, checked_ssub, checked_usub, checked_smul, checked_umul, @@ -1089,6 +1089,16 @@ static Value *emit_intrinsic(intrinsic f, jl_value_t **args, size_t nargs, return builder.CreateExtractValue(res, ArrayRef(0)); } + HANDLE(check_top_bit,1) + // raise InexactError if argument's top bit is set + x = JL_INT(x); + raise_exception_if(builder. + CreateTrunc(builder. + CreateLShr(x, ConstantInt::get(t, t->getPrimitiveSizeInBits()-1)), + T_int1), + prepare_global(jlinexacterr_var), ctx); + return x; + HANDLE(eq_int,2) return builder.CreateICmpEQ(JL_INT(x), JL_INT(y)); HANDLE(ne_int,2) return builder.CreateICmpNE(JL_INT(x), JL_INT(y)); HANDLE(slt_int,2) return builder.CreateICmpSLT(JL_INT(x), JL_INT(y)); @@ -1503,6 +1513,7 @@ extern "C" void jl_init_intrinsic_functions(void) ADD_I(checked_fptosi); ADD_I(checked_fptoui); ADD_I(checked_trunc_sint); ADD_I(checked_trunc_uint); + ADD_I(check_top_bit); ADD_I(nan_dom_err); ADD_I(ccall); ADD_I(cglobal); ADD_I(jl_alloca); diff --git a/test/core.jl b/test/core.jl index cc5c712be1f31..d545b222be4d5 100644 --- a/test/core.jl +++ b/test/core.jl @@ -243,31 +243,31 @@ end # conversions function fooo() local x::Int8 - x = 1000 + x = 100 x end -@test int32(fooo()) == -24 +@test fooo() === convert(Int8,100) function fooo_2() local x::Int8 - x = 1000 + x = 100 end -@test fooo_2() == 1000 +@test fooo_2() === 100 function fooo_3() local x::Int8 - y = x = 1000 - @test x == -24 + y = x = 100 + @test isa(x,Int8) y end -@test fooo_3() == 1000 +@test fooo_3() === 100 function foo() local x::Int8 function bar() - x = 1000 + x = 100 end bar() x end -@test int32(foo()) == -24 +@test foo() === convert(Int8,100) function bar{T}(x::T) local z::Complex{T} diff --git a/test/numbers.jl b/test/numbers.jl index 0c6473cd3a747..5d3620fd7d8b2 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -802,15 +802,15 @@ end for T in {Int8,Int16,Int32,Int64,Int128} @test abs(typemin(T)) == -typemin(T) - for x in {typemin(T),convert(T,-1),zero(T),one(T),typemax(T)} - @test signed(unsigned(x)) == x - end + #for x in {typemin(T),convert(T,-1),zero(T),one(T),typemax(T)} + # @test signed(unsigned(x)) == x + #end end -for T in {Uint8,Uint16,Uint32,Uint64,Uint128}, - x in {typemin(T),one(T),typemax(T)} - @test unsigned(signed(x)) == x -end +#for T in {Uint8,Uint16,Uint32,Uint64,Uint128}, +# x in {typemin(T),one(T),typemax(T)} +# @test unsigned(signed(x)) == x +#end for S = {Int8, Int16, Int32, Int64}, U = {Uint8, Uint16, Uint32, Uint64} @@ -1133,19 +1133,21 @@ end @test cld(typemin(Int64)+3,-2) == 4611686018427387903 @test cld(typemin(Int64)+3,-7) == 1317624576693539401 +import Base.asunsigned + for x={typemin(Int64), -typemax(Int64), -typemax(Int64)+1, -typemax(Int64)+2, typemax(Int64)-2, typemax(Int64)-1, typemax(Int64), typemax(Uint64)-1, typemax(Uint64)-2, typemax(Uint64)}, y={-7,-2,-1,1,2,7} if x >= 0 - @test div(unsigned(x),y) == unsigned(div(x,y)) - @test fld(unsigned(x),y) == unsigned(fld(x,y)) - @test cld(unsigned(x),y) == unsigned(cld(x,y)) + @test div(asunsigned(x),y) == asunsigned(div(x,y)) + @test fld(asunsigned(x),y) == asunsigned(fld(x,y)) + @test cld(asunsigned(x),y) == asunsigned(cld(x,y)) end if isa(x,Signed) && y >= 0 - @test div(x,unsigned(y)) == div(x,y) - @test fld(x,unsigned(y)) == fld(x,y) - @test cld(x,unsigned(y)) == cld(x,y) + @test div(x,asunsigned(y)) == div(x,y) + @test fld(x,asunsigned(y)) == fld(x,y) + @test cld(x,asunsigned(y)) == cld(x,y) end end @@ -1153,19 +1155,19 @@ for x=0:5, y=1:5 @test div(uint(x),uint(y)) == div(x,y) @test div(uint(x),y) == div(x,y) @test div(x,uint(y)) == div(x,y) - @test div(uint(x),-y) == uint(div(x,-y)) + @test div(uint(x),-y) == reinterpret(Uint,div(x,-y)) @test div(-x,uint(y)) == div(-x,y) @test fld(uint(x),uint(y)) == fld(x,y) @test fld(uint(x),y) == fld(x,y) @test fld(x,uint(y)) == fld(x,y) - @test fld(uint(x),-y) == uint(fld(x,-y)) + @test fld(uint(x),-y) == reinterpret(Uint,fld(x,-y)) @test fld(-x,uint(y)) == fld(-x,y) @test cld(uint(x),uint(y)) == cld(x,y) @test cld(uint(x),y) == cld(x,y) @test cld(x,uint(y)) == cld(x,y) - @test cld(uint(x),-y) == uint(cld(x,-y)) + @test cld(uint(x),-y) == reinterpret(Uint,cld(x,-y)) @test cld(-x,uint(y)) == cld(-x,y) @test rem(uint(x),uint(y)) == rem(x,y) @@ -1188,20 +1190,22 @@ end @test div(typemax(Uint64)-2, 1) == typemax(Uint64)-2 @test div(typemax(Uint64)-2,-1) == -typemax(Uint64)+2 -@test signed(div(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 -@test signed(div(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 -@test signed(div(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 -@test signed(div(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 -@test signed(div(unsigned(typemax(Int64)) , 1)) == typemax(Int64) -@test signed(div(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64) - -@test signed(div(typemax(Uint),typemax(Int))) == 2 -@test signed(div(typemax(Uint),(typemax(Int)>>1)+1)) == 3 -@test signed(div(typemax(Uint),typemax(Int)>>1)) == 4 -@test signed(div(typemax(Uint),typemin(Int))) == -1 -@test signed(div(typemax(Uint),typemin(Int)+1)) == -2 -@test signed(div(typemax(Uint),typemin(Int)>>1)) == -3 -@test signed(div(typemax(Uint),(typemin(Int)>>1)+1)) == -4 +using Base.assigned + +@test assigned(div(asunsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 +@test assigned(div(asunsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 +@test assigned(div(asunsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 +@test assigned(div(asunsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 +@test assigned(div(asunsigned(typemax(Int64)) , 1)) == typemax(Int64) +@test assigned(div(asunsigned(typemax(Int64)) ,-1)) == -typemax(Int64) + +@test assigned(div(typemax(Uint),typemax(Int))) == 2 +@test assigned(div(typemax(Uint),(typemax(Int)>>1)+1)) == 3 +@test assigned(div(typemax(Uint),typemax(Int)>>1)) == 4 +@test assigned(div(typemax(Uint),typemin(Int))) == -1 +@test assigned(div(typemax(Uint),typemin(Int)+1)) == -2 +@test assigned(div(typemax(Uint),typemin(Int)>>1)) == -3 +@test assigned(div(typemax(Uint),(typemin(Int)>>1)+1)) == -4 @test fld(typemax(Uint64) , 1) == typemax(Uint64) @test fld(typemax(Uint64) ,-1) == -typemax(Uint64) @@ -1210,20 +1214,20 @@ end @test fld(typemax(Uint64)-2, 1) == typemax(Uint64)-2 @test fld(typemax(Uint64)-2,-1) == -typemax(Uint64)+2 -@test signed(fld(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 -@test signed(fld(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 -@test signed(fld(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 -@test signed(fld(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 -@test signed(fld(unsigned(typemax(Int64)) , 1)) == typemax(Int64) -@test signed(fld(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64) - -@test signed(fld(typemax(Uint),typemax(Int))) == 2 -@test signed(fld(typemax(Uint),(typemax(Int)>>1)+1)) == 3 -@test signed(fld(typemax(Uint),typemax(Int)>>1)) == 4 -@test signed(fld(typemax(Uint),typemin(Int))) == -2 -@test signed(fld(typemax(Uint),typemin(Int)+1)) == -3 -@test signed(fld(typemax(Uint),typemin(Int)>>1)) == -4 -@test signed(fld(typemax(Uint),(typemin(Int)>>1)+1)) == -5 +@test assigned(fld(asunsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 +@test assigned(fld(asunsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 +@test assigned(fld(asunsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 +@test assigned(fld(asunsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 +@test assigned(fld(asunsigned(typemax(Int64)) , 1)) == typemax(Int64) +@test assigned(fld(asunsigned(typemax(Int64)) ,-1)) == -typemax(Int64) + +@test assigned(fld(typemax(Uint),typemax(Int))) == 2 +@test assigned(fld(typemax(Uint),(typemax(Int)>>1)+1)) == 3 +@test assigned(fld(typemax(Uint),typemax(Int)>>1)) == 4 +@test assigned(fld(typemax(Uint),typemin(Int))) == -2 +@test assigned(fld(typemax(Uint),typemin(Int)+1)) == -3 +@test assigned(fld(typemax(Uint),typemin(Int)>>1)) == -4 +@test assigned(fld(typemax(Uint),(typemin(Int)>>1)+1)) == -5 @test cld(typemax(Uint64) , 1) == typemax(Uint64) @test cld(typemax(Uint64) ,-1) == -typemax(Uint64) @@ -1232,20 +1236,20 @@ end @test cld(typemax(Uint64)-2, 1) == typemax(Uint64)-2 @test cld(typemax(Uint64)-2,-1) == -typemax(Uint64)+2 -@test signed(cld(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 -@test signed(cld(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 -@test signed(cld(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 -@test signed(cld(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 -@test signed(cld(unsigned(typemax(Int64)) , 1)) == typemax(Int64) -@test signed(cld(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64) +@test assigned(cld(asunsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 +@test assigned(cld(asunsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 +@test assigned(cld(asunsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 +@test assigned(cld(asunsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 +@test assigned(cld(asunsigned(typemax(Int64)) , 1)) == typemax(Int64) +@test assigned(cld(asunsigned(typemax(Int64)) ,-1)) == -typemax(Int64) @test signed(cld(typemax(Uint),typemax(Int))) == 3 @test signed(cld(typemax(Uint),(typemax(Int)>>1)+1)) == 4 @test signed(cld(typemax(Uint),typemax(Int)>>1)) == 5 -@test signed(cld(typemax(Uint),typemin(Int))) == -1 -@test signed(cld(typemax(Uint),typemin(Int)+1)) == -2 -@test signed(cld(typemax(Uint),typemin(Int)>>1)) == -3 -@test signed(cld(typemax(Uint),(typemin(Int)>>1)+1)) == -4 +@test assigned(cld(typemax(Uint),typemin(Int))) == -1 +@test assigned(cld(typemax(Uint),typemin(Int)+1)) == -2 +@test assigned(cld(typemax(Uint),typemin(Int)>>1)) == -3 +@test assigned(cld(typemax(Uint),(typemin(Int)>>1)+1)) == -4 # issue #4156 @test fld(1.4,0.35667494393873234) == 3.0 From c67837ca8e69505bf684cd71ac11d69a178c86c9 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 19 Sep 2014 10:16:28 -0400 Subject: [PATCH 05/11] get dates tests passing with checked signed<->unsigned conversion --- base/dates/types.jl | 2 +- base/int.jl | 11 +++++++---- base/range.jl | 4 ++-- src/intrinsics.cpp | 3 +++ test/dates/types.jl | 6 +++--- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/base/dates/types.jl b/base/dates/types.jl index 4cde4ca353af7..b1e5e437f2dd0 100644 --- a/base/dates/types.jl +++ b/base/dates/types.jl @@ -160,4 +160,4 @@ Base.promote_rule(::Type{Date},x::Type{DateTime}) = DateTime Base.isless(x::Date,y::Date) = isless(value(x),value(y)) Base.isless(x::DateTime,y::DateTime) = isless(value(x),value(y)) Base.isless(x::TimeType,y::TimeType) = isless(promote(x,y)...) -==(x::TimeType,y::TimeType) = ===(promote(x,y)...) \ No newline at end of file +==(x::TimeType,y::TimeType) = ===(promote(x,y)...) diff --git a/base/int.jl b/base/int.jl index 85760b852cd2d..58382165d7b7e 100644 --- a/base/int.jl +++ b/base/int.jl @@ -43,6 +43,11 @@ abs(x::Signed) = flipsign(x,x) ~(n::Integer) = -n-1 +asunsigned(x::Integer) = reinterpret(typeof(unsigned(zero(x))), x) +asunsigned(x) = unsigned(x) +assigned(x::Integer) = reinterpret(typeof(signed(zero(x))), x) +assigned(x) = signed(x) + div(x::Signed, y::Unsigned) = flipsign(assigned(div(asunsigned(abs(x)),y)),x) div(x::Unsigned, y::Signed) = asunsigned(flipsign(assigned(div(x,asunsigned(abs(y)))),y)) @@ -132,9 +137,6 @@ for T in IntTypes end end -asunsigned(x) = reinterpret(typeof(unsigned(zero(x))), x) -assigned(x) = reinterpret(typeof(signed(zero(x))), x) - ==(x::Signed, y::Unsigned) = (x >= 0) & (asunsigned(x) == y) ==(x::Unsigned, y::Signed ) = (y >= 0) & (x == asunsigned(y)) < (x::Signed, y::Unsigned) = (x < 0) | (asunsigned(x) < y) @@ -227,7 +229,8 @@ int32(x) = convert(Int32,x) int64(x) = convert(Int64,x) int128(x) = convert(Int128,x) -uint8(x) = itrunc(Uint8,x) +uint8(x) = convert(Uint8, x) +uint8(x::Integer) = itrunc(Uint8,x) uint8(x::Int8) = box(Uint8,unbox(Int8,x)) uint16(x) = convert(Uint16,x) uint32(x) = convert(Uint32,x) diff --git a/base/range.jl b/base/range.jl index 6979e3575ffa2..dcda238d4d07f 100644 --- a/base/range.jl +++ b/base/range.jl @@ -39,9 +39,9 @@ immutable StepRange{T,S} <: OrdinalRange{T,S} if T<:Signed && (diff > zero(diff)) != (stop > start) # handle overflowed subtraction with unsigned rem if diff > zero(diff) - remain = -oftype(T, unsigned(-diff) % step) + remain = -oftype(T, asunsigned(-diff) % step) else - remain = oftype(T, unsigned(diff) % step) + remain = oftype(T, asunsigned(diff) % step) end else remain = steprem(start,stop,step) diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index 8f0b0b22b25c9..1a135cfee02a0 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -424,6 +424,9 @@ static Value *generic_box(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) if (vxt != llvmt) { if (vxt == T_void) return vx; + if (!vxt->isSingleValueType()) { + jl_error("box: argument not of a primitive type"); + } if (llvmt == T_int1) { vx = builder.CreateTrunc(vx, llvmt); } diff --git a/test/dates/types.jl b/test/dates/types.jl index c9edf562fce30..ea7e71f0ffaaa 100644 --- a/test/dates/types.jl +++ b/test/dates/types.jl @@ -63,9 +63,9 @@ test = Dates.Date(1,1,1) @test Dates.Date(false,true,true) == test - Dates.Year(1) @test_throws ArgumentError Dates.Date(true,true,false) @test Dates.Date(uint64(1),uint64(1),uint64(1)) == test -@test Dates.Date(0xffffffffffffffff,uint64(1),uint64(1)) == test - Dates.Year(2) +@test Dates.Date(-1,uint64(1),uint64(1)) == test - Dates.Year(2) @test Dates.Date(int128(1),int128(1),int128(1)) == test -@test Dates.Date(170141183460469231731687303715884105727,int128(1),int128(1)) == test - Dates.Year(2) +@test_throws InexactError Dates.Date(170141183460469231731687303715884105727,int128(1),int128(1)) @test Dates.Date(uint128(1),uint128(1),uint128(1)) == test @test Dates.Date(big(1),big(1),big(1)) == test @test Dates.Date(big(1),big(1),big(1)) == test @@ -171,4 +171,4 @@ ms = Dates.Millisecond(1) @test Dates.Date(d,y) == Dates.Date(1,1,1) @test Dates.Date(d,m) == Dates.Date(1,1,1) @test Dates.Date(m,y) == Dates.Date(1,1,1) -=# \ No newline at end of file +=# From ec607da4d3b25663487dd8c5e773d661b6bb6054 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 19 Sep 2014 16:50:29 -0400 Subject: [PATCH 06/11] get a few more things working with checked integer conversions --- base/hashing2.jl | 2 +- base/int.jl | 3 +++ base/random.jl | 5 +++-- base/utf8proc.jl | 4 ++-- src/intrinsics.cpp | 2 +- test/hashing.jl | 19 +++++++++++++++++-- test/reduce.jl | 14 +++++++------- 7 files changed, 34 insertions(+), 15 deletions(-) diff --git a/base/hashing2.jl b/base/hashing2.jl index 342e2dc6c8a93..251ec78faf371 100644 --- a/base/hashing2.jl +++ b/base/hashing2.jl @@ -184,7 +184,7 @@ end function hash(s::IntSet, h::Uint) h += uint(0x88989f1fc7dea67d) h += hash(s.fill1s) - filln = s.fill1s ? uint32(-1) : uint32(0) + filln = s.fill1s ? ~zero(eltype(s.bits)) : zero(eltype(s.bits)) for x in s.bits if x != filln h = hash(x, h) diff --git a/base/int.jl b/base/int.jl index 58382165d7b7e..b55897cba5901 100644 --- a/base/int.jl +++ b/base/int.jl @@ -44,6 +44,7 @@ abs(x::Signed) = flipsign(x,x) ~(n::Integer) = -n-1 asunsigned(x::Integer) = reinterpret(typeof(unsigned(zero(x))), x) +asunsigned(x::Bool) = unsigned(x) asunsigned(x) = unsigned(x) assigned(x::Integer) = reinterpret(typeof(signed(zero(x))), x) assigned(x) = signed(x) @@ -210,6 +211,7 @@ 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{Signed}, x::Bool) = convert(Int,x) convert(::Type{Unsigned}, x::Int8 ) = convert(Uint8,x) convert(::Type{Unsigned}, x::Int16 ) = convert(Uint16,x) @@ -219,6 +221,7 @@ convert(::Type{Unsigned}, x::Int128 ) = convert(Uint128,x) convert(::Type{Unsigned}, x::Float32) = convert(Uint,x) convert(::Type{Unsigned}, x::Float64) = convert(Uint,x) convert(::Type{Unsigned}, x::Char) = convert(Uint,x) +convert(::Type{Unsigned}, x::Bool) = convert(Uint,x) convert(::Type{Integer}, x::Float32) = convert(Int,x) convert(::Type{Integer}, x::Float64) = convert(Int,x) diff --git a/base/random.jl b/base/random.jl index 68f69fb834037..4e58b3bd5184d 100644 --- a/base/random.jl +++ b/base/random.jl @@ -197,7 +197,7 @@ function rand{T<:Union(Uint64, Int64)}(g::RandIntGen{T,Uint64}) x = rand(Uint64) end end - return convert(T, g.a + rem_knuth(x, g.k)) + return reinterpret(T, reinterpret(Uint64, g.a) + rem_knuth(x, g.k)) end function rand{T<:Integer, U<:Unsigned}(g::RandIntGen{T,U}) @@ -205,7 +205,8 @@ function rand{T<:Integer, U<:Unsigned}(g::RandIntGen{T,U}) while x > g.u x = rand(U) end - convert(T, g.a + rem_knuth(x, g.k)) + # TODO: fix for when T is smaller than U + reinterpret(T, Base.asunsigned(g.a) + rem_knuth(x, g.k)) end rand{T<:Union(Signed,Unsigned,Bool,Char)}(r::UnitRange{T}) = rand(RandIntGen(r)) diff --git a/base/utf8proc.jl b/base/utf8proc.jl index b957d1bef39d9..5016b476c3b9c 100644 --- a/base/utf8proc.jl +++ b/base/utf8proc.jl @@ -5,11 +5,11 @@ import Base: show, showcompact, ==, string, symbol, isless # also exported by Base: export normalize_string, is_valid_char, is_assigned_char, - islower, isupper, isalpha, isdigit, isnumber, isalnum, + islower, isupper, isalpha, isdigit, isnumber, isalnum, iscntrl, ispunct, isspace, isprint, isgraph, isblank # whether codepoints are valid Unicode -is_valid_char(c) = bool(ccall(:utf8proc_codepoint_valid, Cchar, (Int32,), c)) +is_valid_char(c) = (0 <= c <= 0x110000) && bool(ccall(:utf8proc_codepoint_valid, Cuchar, (Int32,), c)) # utf8 category constants const UTF8PROC_CATEGORY_LU = 1 diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index c7effe746434b..a171a1b3a10e2 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -439,7 +439,7 @@ static Value *generic_box(jl_value_t *targ, jl_value_t *x, jl_codectx_t *ctx) !(vxt->isPointerTy() && llvmt->getPrimitiveSizeInBits() == sizeof(void*)*8) && !(llvmt->isPointerTy() && vxt->getPrimitiveSizeInBits() == sizeof(void*)*8)) { emit_error("box: argument is of incorrect size", ctx); - return vx; + return UndefValue::get(llvmt); } // PtrToInt and IntToPtr ignore size differences if (vxt->isPointerTy() && !llvmt->isPointerTy()) { diff --git a/test/hashing.jl b/test/hashing.jl index d3f68dbd8e2d1..6bb0f1bff3ad7 100644 --- a/test/hashing.jl +++ b/test/hashing.jl @@ -16,9 +16,24 @@ vals = [ typemax(Int64), ] +function coerce(T::Type, x) + if T<:Rational + return convert(T, coerce(typeof(num(zero(T))), x)) + end + if !(T<:Integer) || T===Bool + convert(T, x) + elseif sizeof(T) < sizeof(x) + itrunc(T, x) + elseif sizeof(T) == sizeof(x) + reinterpret(T, x) + else + convert(T, x) + end +end + for T=types, S=types, x=vals - a = convert(T,x) - b = convert(S,x) + a = coerce(T,x) + b = coerce(S,x) if (isa(a,Char) && !is_valid_char(a)) || (isa(b,Char) && !is_valid_char(b)) continue end diff --git a/test/reduce.jl b/test/reduce.jl index 1799cc9176d39..21652784528b1 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -22,15 +22,15 @@ # sum -@test sum(Int8[]) === 0 -@test sum(Int[]) === 0 +@test sum(Int8[]) === int8(0) +@test sum(Int[]) === int(0) @test sum(Float64[]) === 0.0 @test sum(int8(3)) === int8(3) @test sum(3) === 3 @test sum(3.0) === 3.0 -@test sum([int8(3)]) === 3 +@test sum([int8(3)]) === int8(3) @test sum([3]) === 3 @test sum([3.0]) === 3.0 @@ -49,14 +49,14 @@ fz = float(z) a = randn(32) # need >16 elements to trigger BLAS code path b = complex(randn(32), randn(32)) @test sumabs(Float64[]) === 0.0 -@test sumabs([int8(-2)]) === 2 +@test sumabs([int8(-2)]) === int8(2) @test sumabs(z) === 14 @test sumabs(fz) === 14.0 @test_approx_eq sumabs(a) sum(abs(a)) @test_approx_eq sumabs(b) sum(abs(b)) @test sumabs2(Float64[]) === 0.0 -@test sumabs2([int8(-2)]) === 4 +@test sumabs2([int8(-2)]) === int8(4) @test sumabs2(z) === 54 @test sumabs2(fz) === 54.0 @test_approx_eq sumabs2(a) sum(abs2(a)) @@ -105,8 +105,8 @@ prod(fz) === 120.0 prod2(itr) = invoke(prod, (Any,), itr) @test prod(Int[]) === prod2(Int[]) === 1 @test prod(Int[7]) === prod2(Int[7]) === 7 -@test typeof(prod(Int8[])) == typeof(prod(Int8[1])) == typeof(prod(Int8[1, 7])) == Int -@test typeof(prod2(Int8[])) == typeof(prod2(Int8[1])) == typeof(prod2(Int8[1 7])) == Int +@test typeof(prod(Int8[])) == typeof(prod(Int8[1])) == typeof(prod(Int8[1, 7])) == Int8 +@test typeof(prod2(Int8[])) == typeof(prod2(Int8[1])) == typeof(prod2(Int8[1 7])) == Int8 # maximum & minimum & extrema From 16c2330da55ed9b9eb84353a292db495aad562b7 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 25 Sep 2014 15:18:47 -0400 Subject: [PATCH 07/11] make signed() and unsigned() unchecked. check only in convert() a few fixes in base for the convert and arithmetic changes get all tests passing --- base/char.jl | 4 +- base/datafmt.jl | 2 +- base/grisu/fastfixed.jl | 6 +-- base/int.jl | 48 +++++++++++---------- base/random.jl | 5 +-- base/range.jl | 4 +- base/utf16.jl | 4 +- test/numbers.jl | 94 ++++++++++++++++++++--------------------- 8 files changed, 82 insertions(+), 85 deletions(-) diff --git a/base/char.jl b/base/char.jl index 05cb6124e1c70..606ed400f24de 100644 --- a/base/char.jl +++ b/base/char.jl @@ -10,9 +10,9 @@ convert(::Type{Char}, x::Float64) = char(convert(Uint32, x)) ## char promotions ## promote_rule(::Type{Char}, ::Type{Int8}) = Int32 -promote_rule(::Type{Char}, ::Type{Uint8}) = Int32 +promote_rule(::Type{Char}, ::Type{Uint8}) = Uint32 promote_rule(::Type{Char}, ::Type{Int16}) = Int32 -promote_rule(::Type{Char}, ::Type{Uint16}) = Int32 +promote_rule(::Type{Char}, ::Type{Uint16}) = Uint32 promote_rule(::Type{Char}, ::Type{Int32}) = Int32 promote_rule(::Type{Char}, ::Type{Uint32}) = Uint32 promote_rule(::Type{Char}, ::Type{Int64}) = Int64 diff --git a/base/datafmt.jl b/base/datafmt.jl index a99e97e73f489..e90616443edcf 100644 --- a/base/datafmt.jl +++ b/base/datafmt.jl @@ -338,7 +338,7 @@ function dlm_parse{T,D}(dbuff::T, eol::D, dlm::D, qchar::D, cchar::D, ign_adj_dl all_ascii = (D <: Uint8) || (isascii(eol) && isascii(dlm) && (!allow_quote || isascii(qchar)) && (!allow_comments || isascii(cchar))) (T <: UTF8String) && all_ascii && (return dlm_parse(dbuff.data, uint8(eol), uint8(dlm), uint8(qchar), uint8(cchar), ign_adj_dlm, allow_quote, allow_comments, skipstart, skipblanks, dh)) ncols = nrows = col = 0 - is_default_dlm = (dlm == convert(D, invalid_dlm)) + is_default_dlm = (dlm == itrunc(D, invalid_dlm)) error_str = "" # 0: begin field, 1: quoted field, 2: unquoted field, 3: second quote (could either be end of field or escape character), 4: comment, 5: skipstart state = (skipstart > 0) ? 5 : 0 diff --git a/base/grisu/fastfixed.jl b/base/grisu/fastfixed.jl index 638782727a6bd..22bd4e4e68f54 100644 --- a/base/grisu/fastfixed.jl +++ b/base/grisu/fastfixed.jl @@ -110,8 +110,8 @@ function fillfractionals(fractionals, exponent, return len, decimal_point end -low(x) = uint64(x) -high(x) = uint64(x >> 64) +low(x) = uint64(x&0xffffffffffffffff) +high(x) = uint64(x >>> 64) bitat(x::Uint128,y) = y >= 64 ? (int32(high(x) >> (y-64)) & 1) : (int32(low(x) >> y) & 1) function divrem2(x,power) h = high(x) @@ -219,4 +219,4 @@ function fastfixedtoa(v,mode,fractional_count,buffer) decimal_point = -fractional_count end return true, len, decimal_point, buffer -end \ No newline at end of file +end diff --git a/base/int.jl b/base/int.jl index b55897cba5901..4da95ddd92bdd 100644 --- a/base/int.jl +++ b/base/int.jl @@ -43,23 +43,23 @@ abs(x::Signed) = flipsign(x,x) ~(n::Integer) = -n-1 -asunsigned(x::Integer) = reinterpret(typeof(unsigned(zero(x))), x) -asunsigned(x::Bool) = unsigned(x) -asunsigned(x) = unsigned(x) -assigned(x::Integer) = reinterpret(typeof(signed(zero(x))), x) -assigned(x) = signed(x) +unsigned(x::Signed) = reinterpret(typeof(convert(Unsigned,zero(x))), x) +unsigned(x::Bool) = convert(Unsigned, x) +unsigned(x) = convert(Unsigned, x) +signed(x::Unsigned) = reinterpret(typeof(convert(Signed,zero(x))), x) +signed(x) = convert(Signed, x) -div(x::Signed, y::Unsigned) = flipsign(assigned(div(asunsigned(abs(x)),y)),x) -div(x::Unsigned, y::Signed) = asunsigned(flipsign(assigned(div(x,asunsigned(abs(y)))),y)) +div(x::Signed, y::Unsigned) = flipsign(signed(div(unsigned(abs(x)),y)),x) +div(x::Unsigned, y::Signed) = unsigned(flipsign(signed(div(x,unsigned(abs(y)))),y)) -rem(x::Signed, y::Unsigned) = flipsign(assigned(rem(asunsigned(abs(x)),y)),x) -rem(x::Unsigned, y::Signed) = rem(x,asunsigned(abs(y))) +rem(x::Signed, y::Unsigned) = flipsign(signed(rem(unsigned(abs(x)),y)),x) +rem(x::Unsigned, y::Signed) = rem(x,unsigned(abs(y))) fld(x::Signed, y::Unsigned) = div(x,y)-(signbit(x)&(rem(x,y)!=0)) fld(x::Unsigned, y::Signed) = div(x,y)-(signbit(y)&(rem(x,y)!=0)) -mod(x::Signed, y::Unsigned) = rem(y+asunsigned(rem(x,y)),y) -mod(x::Unsigned, y::Signed) = rem(y+assigned(rem(x,y)),y) +mod(x::Signed, y::Unsigned) = rem(y+unsigned(rem(x,y)),y) +mod(x::Unsigned, y::Signed) = rem(y+signed(rem(x,y)),y) cld(x::Signed, y::Unsigned) = div(x,y)+(!signbit(x)&(rem(x,y)!=0)) cld(x::Unsigned, y::Signed) = div(x,y)+(!signbit(y)&(rem(x,y)!=0)) @@ -138,12 +138,12 @@ for T in IntTypes end end -==(x::Signed, y::Unsigned) = (x >= 0) & (asunsigned(x) == y) -==(x::Unsigned, y::Signed ) = (y >= 0) & (x == asunsigned(y)) -< (x::Signed, y::Unsigned) = (x < 0) | (asunsigned(x) < y) -< (x::Unsigned, y::Signed ) = (y > 0) & (x < asunsigned(y)) -<=(x::Signed, y::Unsigned) = (x <= 0) | (asunsigned(x) <= y) -<=(x::Unsigned, y::Signed ) = (y >= 0) & (x <= asunsigned(y)) +==(x::Signed, y::Unsigned) = (x >= 0) & (unsigned(x) == y) +==(x::Unsigned, y::Signed ) = (y >= 0) & (x == unsigned(y)) +< (x::Signed, y::Unsigned) = (x < 0) | (unsigned(x) < y) +< (x::Unsigned, y::Signed ) = (y > 0) & (x < unsigned(y)) +<=(x::Signed, y::Unsigned) = (x <= 0) | (unsigned(x) <= y) +<=(x::Unsigned, y::Signed ) = (y >= 0) & (x <= unsigned(y)) ## integer conversions ## @@ -165,12 +165,16 @@ for to in tuple(IntTypes...,Char), from in tuple(IntTypes...,Char,Bool) elseif !(issubtype(from,Signed) === issubtype(to,Signed)) # raise InexactError if x's top bit is set @eval convert(::Type{$to}, x::($from)) = box($to,check_top_bit(unbox($from,x))) + @eval itrunc(::Type{$to}, x::($from)) = box($to,unbox($from,x)) else @eval convert(::Type{$to}, x::($from)) = box($to,unbox($from,x)) end end end +itrunc{T<:Integer}(::Type{T}, x::T) = x +itrunc(::Type{Bool}, x::Integer) = ((x&1)!=0) + for to in (Int8, Int16, Int32, Int64) @eval begin convert(::Type{$to}, x::Float32) = box($to,checked_fptosi($to,unbox(Float32,x))) @@ -240,8 +244,6 @@ uint32(x) = convert(Uint32,x) uint64(x) = convert(Uint64,x) uint128(x) = convert(Uint128,x) -signed(x) = convert(Signed,x) -unsigned(x) = convert(Unsigned,x) integer(x) = convert(Integer,x) round(x::Integer) = x @@ -356,12 +358,12 @@ typemax(::Type{Uint64}) = 0xffffffffffffffff @eval typemin(::Type{Int128} ) = $(convert(Int128,1)<>int32(1)))) -widen(::Type{Int8}) = Int16 -widen(::Type{Int16}) = Int32 +widen(::Type{Int8}) = Int +widen(::Type{Int16}) = Int widen(::Type{Int32}) = Int64 widen(::Type{Int64}) = Int128 -widen(::Type{Uint8}) = Uint16 -widen(::Type{Uint16}) = Uint32 +widen(::Type{Uint8}) = Uint +widen(::Type{Uint16}) = Uint widen(::Type{Uint32}) = Uint64 widen(::Type{Uint64}) = Uint128 diff --git a/base/random.jl b/base/random.jl index 4e58b3bd5184d..70c439cbb705e 100644 --- a/base/random.jl +++ b/base/random.jl @@ -179,7 +179,7 @@ for (T, U) in [(Uint8, Uint32), (Uint16, Uint32), (Int8, Uint32), (Int16, Uint32), (Int32, Uint32), (Int64, Uint64), (Int128, Uint128), (Bool, Uint32), (Char, Uint32)] - @eval RandIntGen(r::UnitRange{$T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert($U, last(r) - first(r) + 1)) # overflow ok + @eval RandIntGen(r::UnitRange{$T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert($U, unsigned(last(r) - first(r) + one($T)))) # overflow ok end # this function uses 32 bit entropy for small ranges of length <= typemax(Uint32) + 1 @@ -205,8 +205,7 @@ function rand{T<:Integer, U<:Unsigned}(g::RandIntGen{T,U}) while x > g.u x = rand(U) end - # TODO: fix for when T is smaller than U - reinterpret(T, Base.asunsigned(g.a) + rem_knuth(x, g.k)) + itrunc(T, g.a + rem_knuth(x, g.k)) end rand{T<:Union(Signed,Unsigned,Bool,Char)}(r::UnitRange{T}) = rand(RandIntGen(r)) diff --git a/base/range.jl b/base/range.jl index dcda238d4d07f..6979e3575ffa2 100644 --- a/base/range.jl +++ b/base/range.jl @@ -39,9 +39,9 @@ immutable StepRange{T,S} <: OrdinalRange{T,S} if T<:Signed && (diff > zero(diff)) != (stop > start) # handle overflowed subtraction with unsigned rem if diff > zero(diff) - remain = -oftype(T, asunsigned(-diff) % step) + remain = -oftype(T, unsigned(-diff) % step) else - remain = oftype(T, asunsigned(diff) % step) + remain = oftype(T, unsigned(diff) % step) end else remain = steprem(start,stop,step) diff --git a/base/utf16.jl b/base/utf16.jl index 29c496dca7f6e..be313bacae6d8 100644 --- a/base/utf16.jl +++ b/base/utf16.jl @@ -11,7 +11,7 @@ end utf16_is_lead(c::Uint16) = (c & 0xfc00) == 0xd800 utf16_is_trail(c::Uint16) = (c & 0xfc00) == 0xdc00 utf16_is_surrogate(c::Uint16) = (c & 0xf800) == 0xd800 -utf16_get_supplementary(lead::Uint16, trail::Uint16) = char((lead-0xd7f7)<<10 + trail) +utf16_get_supplementary(lead::Uint16, trail::Uint16) = char(uint32(lead-0xd7f7)<<10 + trail) function endof(s::UTF16String) d = s.data @@ -91,7 +91,7 @@ convert(T::Type{UTF16String}, data::AbstractArray{Int16}) = function convert(T::Type{UTF16String}, bytes::AbstractArray{Uint8}) isempty(bytes) && return UTF16String(Uint16[0]) isodd(length(bytes)) && throw(ArgumentError("odd number of bytes")) - data = reinterpret(Uint16, bytes) + data = reinterpret(Uint16, bytes) # check for byte-order mark (BOM): if data[1] == 0xfeff # native byte order d = Array(Uint16, length(data)) diff --git a/test/numbers.jl b/test/numbers.jl index 5d3620fd7d8b2..5606e1035322c 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1133,21 +1133,19 @@ end @test cld(typemin(Int64)+3,-2) == 4611686018427387903 @test cld(typemin(Int64)+3,-7) == 1317624576693539401 -import Base.asunsigned - for x={typemin(Int64), -typemax(Int64), -typemax(Int64)+1, -typemax(Int64)+2, typemax(Int64)-2, typemax(Int64)-1, typemax(Int64), typemax(Uint64)-1, typemax(Uint64)-2, typemax(Uint64)}, y={-7,-2,-1,1,2,7} if x >= 0 - @test div(asunsigned(x),y) == asunsigned(div(x,y)) - @test fld(asunsigned(x),y) == asunsigned(fld(x,y)) - @test cld(asunsigned(x),y) == asunsigned(cld(x,y)) + @test div(unsigned(x),y) == unsigned(div(x,y)) + @test fld(unsigned(x),y) == unsigned(fld(x,y)) + @test cld(unsigned(x),y) == unsigned(cld(x,y)) end if isa(x,Signed) && y >= 0 - @test div(x,asunsigned(y)) == div(x,y) - @test fld(x,asunsigned(y)) == fld(x,y) - @test cld(x,asunsigned(y)) == cld(x,y) + @test div(x,unsigned(y)) == div(x,y) + @test fld(x,unsigned(y)) == fld(x,y) + @test cld(x,unsigned(y)) == cld(x,y) end end @@ -1190,22 +1188,20 @@ end @test div(typemax(Uint64)-2, 1) == typemax(Uint64)-2 @test div(typemax(Uint64)-2,-1) == -typemax(Uint64)+2 -using Base.assigned - -@test assigned(div(asunsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 -@test assigned(div(asunsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 -@test assigned(div(asunsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 -@test assigned(div(asunsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 -@test assigned(div(asunsigned(typemax(Int64)) , 1)) == typemax(Int64) -@test assigned(div(asunsigned(typemax(Int64)) ,-1)) == -typemax(Int64) - -@test assigned(div(typemax(Uint),typemax(Int))) == 2 -@test assigned(div(typemax(Uint),(typemax(Int)>>1)+1)) == 3 -@test assigned(div(typemax(Uint),typemax(Int)>>1)) == 4 -@test assigned(div(typemax(Uint),typemin(Int))) == -1 -@test assigned(div(typemax(Uint),typemin(Int)+1)) == -2 -@test assigned(div(typemax(Uint),typemin(Int)>>1)) == -3 -@test assigned(div(typemax(Uint),(typemin(Int)>>1)+1)) == -4 +@test signed(div(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 +@test signed(div(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 +@test signed(div(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 +@test signed(div(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 +@test signed(div(unsigned(typemax(Int64)) , 1)) == typemax(Int64) +@test signed(div(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64) + +@test signed(div(typemax(Uint),typemax(Int))) == 2 +@test signed(div(typemax(Uint),(typemax(Int)>>1)+1)) == 3 +@test signed(div(typemax(Uint),typemax(Int)>>1)) == 4 +@test signed(div(typemax(Uint),typemin(Int))) == -1 +@test signed(div(typemax(Uint),typemin(Int)+1)) == -2 +@test signed(div(typemax(Uint),typemin(Int)>>1)) == -3 +@test signed(div(typemax(Uint),(typemin(Int)>>1)+1)) == -4 @test fld(typemax(Uint64) , 1) == typemax(Uint64) @test fld(typemax(Uint64) ,-1) == -typemax(Uint64) @@ -1214,20 +1210,20 @@ using Base.assigned @test fld(typemax(Uint64)-2, 1) == typemax(Uint64)-2 @test fld(typemax(Uint64)-2,-1) == -typemax(Uint64)+2 -@test assigned(fld(asunsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 -@test assigned(fld(asunsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 -@test assigned(fld(asunsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 -@test assigned(fld(asunsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 -@test assigned(fld(asunsigned(typemax(Int64)) , 1)) == typemax(Int64) -@test assigned(fld(asunsigned(typemax(Int64)) ,-1)) == -typemax(Int64) - -@test assigned(fld(typemax(Uint),typemax(Int))) == 2 -@test assigned(fld(typemax(Uint),(typemax(Int)>>1)+1)) == 3 -@test assigned(fld(typemax(Uint),typemax(Int)>>1)) == 4 -@test assigned(fld(typemax(Uint),typemin(Int))) == -2 -@test assigned(fld(typemax(Uint),typemin(Int)+1)) == -3 -@test assigned(fld(typemax(Uint),typemin(Int)>>1)) == -4 -@test assigned(fld(typemax(Uint),(typemin(Int)>>1)+1)) == -5 +@test signed(fld(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 +@test signed(fld(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 +@test signed(fld(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 +@test signed(fld(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 +@test signed(fld(unsigned(typemax(Int64)) , 1)) == typemax(Int64) +@test signed(fld(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64) + +@test signed(fld(typemax(Uint),typemax(Int))) == 2 +@test signed(fld(typemax(Uint),(typemax(Int)>>1)+1)) == 3 +@test signed(fld(typemax(Uint),typemax(Int)>>1)) == 4 +@test signed(fld(typemax(Uint),typemin(Int))) == -2 +@test signed(fld(typemax(Uint),typemin(Int)+1)) == -3 +@test signed(fld(typemax(Uint),typemin(Int)>>1)) == -4 +@test signed(fld(typemax(Uint),(typemin(Int)>>1)+1)) == -5 @test cld(typemax(Uint64) , 1) == typemax(Uint64) @test cld(typemax(Uint64) ,-1) == -typemax(Uint64) @@ -1236,20 +1232,20 @@ using Base.assigned @test cld(typemax(Uint64)-2, 1) == typemax(Uint64)-2 @test cld(typemax(Uint64)-2,-1) == -typemax(Uint64)+2 -@test assigned(cld(asunsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 -@test assigned(cld(asunsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 -@test assigned(cld(asunsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 -@test assigned(cld(asunsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 -@test assigned(cld(asunsigned(typemax(Int64)) , 1)) == typemax(Int64) -@test assigned(cld(asunsigned(typemax(Int64)) ,-1)) == -typemax(Int64) +@test signed(cld(unsigned(typemax(Int64))+2, 1)) == typemax(Int64)+2 +@test signed(cld(unsigned(typemax(Int64))+2,-1)) == -typemax(Int64)-2 +@test signed(cld(unsigned(typemax(Int64))+1, 1)) == typemax(Int64)+1 +@test signed(cld(unsigned(typemax(Int64))+1,-1)) == -typemax(Int64)-1 +@test signed(cld(unsigned(typemax(Int64)) , 1)) == typemax(Int64) +@test signed(cld(unsigned(typemax(Int64)) ,-1)) == -typemax(Int64) @test signed(cld(typemax(Uint),typemax(Int))) == 3 @test signed(cld(typemax(Uint),(typemax(Int)>>1)+1)) == 4 @test signed(cld(typemax(Uint),typemax(Int)>>1)) == 5 -@test assigned(cld(typemax(Uint),typemin(Int))) == -1 -@test assigned(cld(typemax(Uint),typemin(Int)+1)) == -2 -@test assigned(cld(typemax(Uint),typemin(Int)>>1)) == -3 -@test assigned(cld(typemax(Uint),(typemin(Int)>>1)+1)) == -4 +@test signed(cld(typemax(Uint),typemin(Int))) == -1 +@test signed(cld(typemax(Uint),typemin(Int)+1)) == -2 +@test signed(cld(typemax(Uint),typemin(Int)>>1)) == -3 +@test signed(cld(typemax(Uint),(typemin(Int)>>1)+1)) == -4 # issue #4156 @test fld(1.4,0.35667494393873234) == 3.0 @@ -1935,7 +1931,7 @@ end # widen @test widen(1.5f0) === 1.5 @test widen(int32(42)) === int64(42) -@test widen(Int8) === Int16 +@test widen(Int8) === Int @test widen(Float32) === Float64 ## Note: this should change to e.g. Float128 at some point @test widen(Float64) === BigFloat From 9f0ef0d4f56cae1e5a6d4ff98330264fe7e15774 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 25 Sep 2014 16:18:07 -0400 Subject: [PATCH 08/11] add a bit of widening to reductions, to make up for the new type-preserving arithmetic. allow reducedim(+, A, 2), which previously gave ``` ERROR: `reducedim_init` has no method matching reducedim_init(::IdFun, ::Function, ::Array{Uint8,2}, ::Int64) in reducedim at reducedim.jl:217 ``` --- base/reduce.jl | 24 ++++++++++++++++++++---- base/reducedim.jl | 34 +++++++++++++++------------------- test/arrayops.jl | 1 + test/reduce.jl | 12 ++++++------ 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index 8b114f73ef8d1..f406d56e39263 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -39,10 +39,26 @@ evaluate(f::Callable, x, y) = f(x, y) ###### Generic (map)reduce functions ###### +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) +typealias WidenReduceResult Union(SmallSigned, SmallUnsigned, Float16) + # r_promote: promote x to the type of reduce(op, [x]) +r_promote(op, x::WidenReduceResult) = widen(x) r_promote(op, x) = x -r_promote(::AddFun, x) = x + zero(x) -r_promote(::MulFun, x) = x * one(x) +r_promote(::AddFun, x::WidenReduceResult) = widen(x) +r_promote(::MulFun, x::WidenReduceResult) = widen(x) +r_promote(::AddFun, x::Number) = x + zero(x) +r_promote(::MulFun, x::Number) = x * one(x) +r_promote(::AddFun, x) = x +r_promote(::MulFun, x) = x ## foldl && mapfoldl @@ -155,8 +171,8 @@ function _mapreduce{T}(f, op, A::AbstractArray{T}) elseif n == 1 return r_promote(op, evaluate(f, A[1])) elseif n < 16 - @inbounds fx1 = evaluate(f, A[1]) - @inbounds fx2 = evaluate(f, A[2]) + @inbounds fx1 = r_promote(op, evaluate(f, A[1])) + @inbounds fx2 = r_promote(op, evaluate(f, A[2])) s = evaluate(op, fx1, fx2) i = 2 while i < n diff --git a/base/reducedim.jl b/base/reducedim.jl index 23d65ab898c47..8550e4aaa4046 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -101,16 +101,6 @@ 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)) T = Union([AbstractArray{t} for t in IT.types]..., [AbstractArray{Complex{t}} for t in IT.types]...) @eval begin @@ -200,18 +190,24 @@ end mapreducedim!(f, op, R::AbstractArray, A::AbstractArray) = _mapreducedim!(f, op, R, A) -function mapreducedim!(f::Function, op, R::AbstractArray, A::AbstractArray) - is(op, +) ? _mapreducedim!(f, AddFun(), R, A) : - is(op, *) ? _mapreducedim!(f, MulFun(), R, A) : - is(op, &) ? _mapreducedim!(f, AndFun(), R, A) : - is(op, |) ? _mapreducedim!(f, OrFun(), R, A) : - _mapreducedim!(f, op, R, A) +to_op(op) = op +function to_op(op::Function) + is(op, +) ? AddFun() : + is(op, *) ? MulFun() : + is(op, &) ? AndFun() : + is(op, |) ? OrFun() : op end -reducedim!{RT}(op, R::AbstractArray{RT}, A::AbstractArray) = mapreducedim!(IdFun(), op, R, A, zero(RT)) +mapreducedim!(f::Function, op, R::AbstractArray, A::AbstractArray) = + _mapreducedim!(f, to_op(op), R, A) + +reducedim!{RT}(op, R::AbstractArray{RT}, A::AbstractArray) = + mapreducedim!(IdFun(), op, R, A, zero(RT)) -mapreducedim(f, op, A::AbstractArray, region, v0) = mapreducedim!(f, op, reducedim_initarray(A, region, v0), A) -mapreducedim{T}(f, op, A::AbstractArray{T}, region) = mapreducedim!(f, op, reducedim_init(f, op, A, region), A) +mapreducedim(f, op, A::AbstractArray, region, v0) = + mapreducedim!(f, op, reducedim_initarray(A, region, v0), A) +mapreducedim{T}(f, op, A::AbstractArray{T}, region) = + mapreducedim!(f, op, reducedim_init(f, to_op(op), A, region), A) reducedim(op, A::AbstractArray, region, v0) = mapreducedim(IdFun(), op, A, region, v0) reducedim(op, A::AbstractArray, region) = mapreducedim(IdFun(), op, A, region) diff --git a/test/arrayops.jl b/test/arrayops.jl index 2c16074ad6c0b..0d1116a70239b 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -675,6 +675,7 @@ begin # other types than Number @test mapslices(prod,["1" "2"; "3" "4"],1) == ["13" "24"] + @test mapslices(prod,["1"],1) == ["1"] # issue #5177 diff --git a/test/reduce.jl b/test/reduce.jl index 21652784528b1..0f5ac545020fc 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -22,7 +22,7 @@ # sum -@test sum(Int8[]) === int8(0) +@test sum(Int8[]) === 0 @test sum(Int[]) === int(0) @test sum(Float64[]) === 0.0 @@ -30,7 +30,7 @@ @test sum(3) === 3 @test sum(3.0) === 3.0 -@test sum([int8(3)]) === int8(3) +@test sum([int8(3)]) === 3 @test sum([3]) === 3 @test sum([3.0]) === 3.0 @@ -49,14 +49,14 @@ fz = float(z) a = randn(32) # need >16 elements to trigger BLAS code path b = complex(randn(32), randn(32)) @test sumabs(Float64[]) === 0.0 -@test sumabs([int8(-2)]) === int8(2) +@test sumabs([int8(-2)]) === 2 @test sumabs(z) === 14 @test sumabs(fz) === 14.0 @test_approx_eq sumabs(a) sum(abs(a)) @test_approx_eq sumabs(b) sum(abs(b)) @test sumabs2(Float64[]) === 0.0 -@test sumabs2([int8(-2)]) === int8(4) +@test sumabs2([int8(-2)]) === 4 @test sumabs2(z) === 54 @test sumabs2(fz) === 54.0 @test_approx_eq sumabs2(a) sum(abs2(a)) @@ -105,8 +105,8 @@ prod(fz) === 120.0 prod2(itr) = invoke(prod, (Any,), itr) @test prod(Int[]) === prod2(Int[]) === 1 @test prod(Int[7]) === prod2(Int[7]) === 7 -@test typeof(prod(Int8[])) == typeof(prod(Int8[1])) == typeof(prod(Int8[1, 7])) == Int8 -@test typeof(prod2(Int8[])) == typeof(prod2(Int8[1])) == typeof(prod2(Int8[1 7])) == Int8 +@test typeof(prod(Int8[])) == typeof(prod(Int8[1])) == typeof(prod(Int8[1, 7])) == Int +@test typeof(prod2(Int8[])) == typeof(prod2(Int8[1])) == typeof(prod2(Int8[1 7])) == Int # maximum & minimum & extrema From 3336fbc72668f47f66fc71df9b9750899b7bd1eb Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 26 Sep 2014 10:07:02 -0400 Subject: [PATCH 09/11] fix more cases of widening in reductions also fix sum_kbn on empty input --- base/reduce.jl | 16 ++++++++-------- test/reduce.jl | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/base/reduce.jl b/base/reduce.jl index c0b5003befefb..4c0d59d72b656 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -126,7 +126,7 @@ foldr(op, itr) = mapfoldr(IdFun(), op, itr) # mapreduce_***_impl require ifirst < ilast function mapreduce_seq_impl(f, op, A::AbstractArray, ifirst::Int, ilast::Int) - @inbounds fx1 = evaluate(f, A[ifirst]) + @inbounds fx1 = r_promote(op, evaluate(f, A[ifirst])) @inbounds fx2 = evaluate(f, A[ifirst+=1]) @inbounds v = evaluate(op, fx1, fx2) while ifirst < ilast @@ -208,7 +208,7 @@ reduce(op, a::Number) = a function mapreduce_seq_impl(f, op::AddFun, a::AbstractArray, ifirst::Int, ilast::Int) @inbounds if ifirst + 6 >= ilast # length(a) < 8 i = ifirst - s = evaluate(f, a[i]) + evaluate(f, a[i+1]) + s = r_promote(op, evaluate(f, a[i])) + evaluate(f, a[i+1]) i = i+1 while i < ilast s += evaluate(f, a[i+=1]) @@ -216,10 +216,10 @@ function mapreduce_seq_impl(f, op::AddFun, a::AbstractArray, ifirst::Int, ilast: return s else # length(a) >= 8, manual unrolling - s1 = evaluate(f, a[ifirst]) + evaluate(f, a[ifirst + 4]) - s2 = evaluate(f, a[ifirst + 1]) + evaluate(f, a[ifirst + 5]) - s3 = evaluate(f, a[ifirst + 2]) + evaluate(f, a[ifirst + 6]) - s4 = evaluate(f, a[ifirst + 3]) + evaluate(f, a[ifirst + 7]) + s1 = r_promote(op, evaluate(f, a[ifirst])) + evaluate(f, a[ifirst + 4]) + s2 = r_promote(op, evaluate(f, a[ifirst + 1])) + evaluate(f, a[ifirst + 5]) + s3 = r_promote(op, evaluate(f, a[ifirst + 2])) + evaluate(f, a[ifirst + 6]) + s4 = r_promote(op, evaluate(f, a[ifirst + 3])) + evaluate(f, a[ifirst + 7]) i = ifirst + 8 il = ilast - 3 while i <= il @@ -256,10 +256,10 @@ sumabs2(a) = mapreduce(Abs2Fun(), AddFun(), a) # of a considerable increase in computational expense. function sum_kbn{T<:FloatingPoint}(A::AbstractArray{T}) n = length(A) + c = r_promote(AddFun(), zero(T)::T) if n == 0 - return sumzero(T) + return c end - c = zero(T) s = A[1] + c for i in 2:n @inbounds Ai = A[i] diff --git a/test/reduce.jl b/test/reduce.jl index 0f5ac545020fc..349e8b897952a 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -87,6 +87,7 @@ end @test typeof(sum(Int8[])) == typeof(sum(Int8[1])) == typeof(sum(Int8[1 7])) @test sum_kbn([1,1e100,1,-1e100]) == 2 +@test sum_kbn(Float64[]) == 0.0 # prod @@ -214,3 +215,5 @@ end @test isequal(cummin([1 0; 0 1], 1), [1 0; 0 0]) @test isequal(cummin([1 0; 0 1], 2), [1 0; 0 0]) +@test sum(collect(uint8(0:255))) == 32640 +@test sum(collect(uint8(254:255))) == 509 From 4d1c13821726bce16045bec36f6f4e8304e87a4f Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Fri, 26 Sep 2014 12:44:03 -0400 Subject: [PATCH 10/11] fix more issues with integer conversion in random number generation --- base/int.jl | 2 ++ base/random.jl | 13 +++++++------ test/random.jl | 6 ++++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/base/int.jl b/base/int.jl index 4da95ddd92bdd..257872a7a5d62 100644 --- a/base/int.jl +++ b/base/int.jl @@ -239,6 +239,8 @@ int128(x) = convert(Int128,x) uint8(x) = convert(Uint8, x) uint8(x::Integer) = itrunc(Uint8,x) uint8(x::Int8) = box(Uint8,unbox(Int8,x)) +uint8(x::Bool) = convert(Uint8, x) + uint16(x) = convert(Uint16,x) uint32(x) = convert(Uint32,x) uint64(x) = convert(Uint64,x) diff --git a/base/random.jl b/base/random.jl index 70c439cbb705e..ae199e570bf84 100644 --- a/base/random.jl +++ b/base/random.jl @@ -154,12 +154,12 @@ rem_knuth{T<:Unsigned}(a::T, b::T) = b != 0 ? a % b : a # maximum multiple of k <= 2^bits(T) decremented by one, # that is 0xFFFFFFFF if k = typemax(T) - typemin(T) with intentional underflow -maxmultiple(k::Uint32) = convert(Uint32, div(0x0000000100000000,k + (k == 0))*k - 1) -maxmultiple(k::Uint64) = convert(Uint64, div(0x00000000000000010000000000000000, k + (k == 0))*k - 1) +maxmultiple(k::Uint32) = itrunc(Uint32, div(0x0000000100000000,k + (k == 0))*k - 1) +maxmultiple(k::Uint64) = itrunc(Uint64, div(0x00000000000000010000000000000000, k + (k == 0))*k - 1) # maximum multiple of k within 1:typemax(Uint128) maxmultiple(k::Uint128) = div(typemax(Uint128), k + (k == 0))*k - 1 # maximum multiple of k within 1:2^32 or 1:2^64, depending on size -maxmultiplemix(k::Uint64) = convert(Uint64, div((k >> 32 != 0)*0x0000000000000000FFFFFFFF00000000 + 0x0000000100000000, k + (k == 0))*k - 1) +maxmultiplemix(k::Uint64) = itrunc(Uint64, div((k >> 32 != 0)*0x0000000000000000FFFFFFFF00000000 + 0x0000000100000000, k + (k == 0))*k - 1) immutable RandIntGen{T<:Integer, U<:Unsigned} a::T # first element of the range @@ -173,13 +173,14 @@ RandIntGen{T}(a::T, k::Uint64) = RandIntGen{T,Uint64}(a, k, maxmultiplemix(k)) # generator for ranges -RandIntGen{T<:Unsigned}(r::UnitRange{T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert(T,last(r) - first(r) + 1)) +RandIntGen{T<:Unsigned}(r::UnitRange{T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), last(r) - first(r) + one(T)) + # specialized versions for (T, U) in [(Uint8, Uint32), (Uint16, Uint32), (Int8, Uint32), (Int16, Uint32), (Int32, Uint32), (Int64, Uint64), (Int128, Uint128), (Bool, Uint32), (Char, Uint32)] - @eval RandIntGen(r::UnitRange{$T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert($U, unsigned(last(r) - first(r) + one($T)))) # overflow ok + @eval RandIntGen(r::UnitRange{$T}) = isempty(r) ? error("range must be non-empty") : RandIntGen(first(r), convert($U, unsigned(last(r) - first(r)) + one($U))) # overflow ok end # this function uses 32 bit entropy for small ranges of length <= typemax(Uint32) + 1 @@ -205,7 +206,7 @@ function rand{T<:Integer, U<:Unsigned}(g::RandIntGen{T,U}) while x > g.u x = rand(U) end - itrunc(T, g.a + rem_knuth(x, g.k)) + itrunc(T, unsigned(g.a) + rem_knuth(x, g.k)) end rand{T<:Union(Signed,Unsigned,Bool,Char)}(r::UnitRange{T}) = rand(RandIntGen(r)) diff --git a/test/random.jl b/test/random.jl index e0d6d1318622f..9e9970f208172 100644 --- a/test/random.jl +++ b/test/random.jl @@ -42,6 +42,12 @@ for T in (Int8, Uint8, Int16, Uint16, Int32, Uint32, Int64, Uint64, Int128, Uint @test typeof(r) == T @test 97 <= r <= 122 @test mod(r,2)==1 + + if T<:Integer && T!==Char + x = rand(typemin(T):typemax(T)) + @test isa(x,T) + @test typemin(T) <= x <= typemax(T) + end end if sizeof(Int32) < sizeof(Int) From 8321a9efce0da0081f01dbf39e44e16413b07265 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Sun, 28 Sep 2014 14:11:49 -0400 Subject: [PATCH 11/11] doc and test updates for checked integer conversions --- doc/stdlib/base.rst | 6 +++--- test/numbers.jl | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index e96964a9a8861..ccd7e90df6e10 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -235,7 +235,7 @@ All Objects .. function:: convert(type, x) - Try to convert ``x`` to the given type. Conversions from floating point to integer, rational to integer, and complex to real will raise an ``InexactError`` if ``x`` cannot be represented exactly in the new type. + Try to convert ``x`` to the given type. Conversion to a different numeric type will raise an ``InexactError`` if ``x`` cannot be represented exactly in the new type. .. function:: promote(xs...) @@ -3545,11 +3545,11 @@ Data Formats .. function:: signed(x) - Convert a number to a signed integer + Convert a number to a signed integer. If the argument is unsigned, it is reinterpreted as signed without checking for overflow. .. function:: unsigned(x) -> Unsigned - Convert a number to an unsigned integer + Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as unsigned without checking for negative values. .. function:: int8(x) diff --git a/test/numbers.jl b/test/numbers.jl index 5606e1035322c..c5ac9bc5e759f 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1983,3 +1983,8 @@ let a = zeros(Int, 3) @test a == [1, 1, 1] end +@test_throws InexactError convert(Uint8, 256) +@test_throws InexactError convert(Uint, -1) +@test_throws InexactError convert(Int, big(2)^100) +@test_throws InexactError convert(Int16, big(2)^100) +@test_throws InexactError convert(Int, typemax(Uint))