diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index e065328356ff56..3f6437669cb576 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -2260,14 +2260,6 @@ for sets of arbitrary objects. """ Set -""" - signed(x) - -Convert a number to a signed integer. If the argument is unsigned, it is reinterpreted as -signed without checking for overflow. -""" -signed - """ Val{c} diff --git a/base/essentials.jl b/base/essentials.jl index ac24cc77a75f4f..8a419f44e75848 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -144,20 +144,54 @@ oftype(x,c) = convert(typeof(x),c) Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as unsigned without checking for negative values. +See also [`signed`](@ref). unsigned(T::Type) -> UnsignedType -Return the return-type of unsigned(x::T). +Return the return-type of `unsigned(x::T)`, so that `unsigned(x)::unsigned(typeof(x))`. ```jldoctest julia> unsigned(12) 0x000000000000000c -julia> unsigned(Int) +julia> unsigned(Int64) UInt64 + +julia> unsigned(2.0) +0x0000000000000002 + +julia> unsigned(2.2) +ERROR: InexactError() +[...] ``` """ unsigned(x::Int) = reinterpret(UInt, x) + +""" + signed(x) + +Convert a number to a signed integer. If the argument is unsigned, it is reinterpreted as +signed without checking for overflow. +See also [`unsigned`](@ref). + + signed(T::Type) -> SignedType + +Return the return-type of `signed(x::T)`, so that `signed(x)::signed(typeof(x))`. + +```jldoctest +julia> signed(0xc) +12 + +julia> signed(UInt64) +Int64 + +julia> signed(2.0) +2 + +julia> signed(2.2) +ERROR: InexactError() +[...] +""" signed(x::UInt) = reinterpret(Int, x) # conversions used by ccall diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 549e4d202b2042..90e46d2659d7fb 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -29,9 +29,17 @@ maxintfloat() = maxintfloat(Float64) isinteger(x::AbstractFloat) = (x - trunc(x) == 0) +""" + hex2num(str) + +Convert a hexadecimal string to the floating point number it represents. +This function, which is inherently type-unstable, returns a `Float16`, +a `Float32`, or a `Float64` depending on the length of the string `str` +(note that this length must hence be no greater than 16). +""" function hex2num(s::AbstractString) l = length(s) - l > 16 && throw(ArgumentError("the passed string must be of length <= 16, got $l")) + l > 16 && throw(ArgumentError("the length of the passed string must be <= 16, got $l")) hex2num(l <= 4 ? Float16 : l <= 8 ? Float32 : Float64, s) end diff --git a/base/int.jl b/base/int.jl index 94b1202d3feb80..eba82b1dacbb7a 100644 --- a/base/int.jl +++ b/base/int.jl @@ -29,7 +29,34 @@ const BitReal_types = (BitInteger_types..., BitFloat_types...) const BitReal = Union{BitReal_types...} reinterpret(::Type{Unsigned}, x::BitInteger) = unsigned(x) - +reinterpret(::Type{ Signed}, x::BitInteger) = signed(x) + +unsigned(::Type{T}) where {T<:Unsigned} = T +signed( ::Type{T}) where {T<:Signed} = T + +unsigned(::Type{<:Union{Bool,BitFloat}}) = UInt +signed( ::Type{<:Union{Bool,BitFloat}}) = Int + + +isdefined(Main, :Base) && # zip (etc.) not available when running in Core + for (S,U,F) in zip(BitSigned_types, BitUnsigned_types, + [nothing, Float16, Float32, Float64, nothing]) + @eval begin + unsigned(::Type{$S}) = $U + unsigned(::Type{$U}) = $U + signed( ::Type{$S}) = $S + signed( ::Type{$U}) = $S + reinterpret(::Type{Unsigned}, ::Type{$S}) = $U + reinterpret(::Type{Unsigned}, ::Type{$U}) = $U + reinterpret(::Type{Signed}, ::Type{$S}) = $S + reinterpret(::Type{Signed}, ::Type{$U}) = $S + end + F === nothing && continue + @eval begin + reinterpret(::Type{Unsigned}, ::Type{$F}) = $U + reinterpret(::Type{Signed}, ::Type{$F}) = $S + end + end ## integer comparisons ## diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 7fd538a9d99869..6c7f129ed5cb3f 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -1,5 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license + ## number-theoretic functions ## """ @@ -488,7 +489,7 @@ end An hexadecimal string of the binary representation of a number. See also the [`bits`](@ref) function, which is similar but gives -a binary string. +a binary string, and [`hex2num`] which does the opposite conversion. ```jldoctest julia> num2hex(Int64(4)) @@ -515,16 +516,9 @@ julia> hex2num(Float64, "400199999999999a") julia> hex2num(Int32, "fffffffe") -2 ``` - - hex2num(str) - -Convert a hexadecimal string to the floating point number it represents. -This function, which is inherently type-unstable, returns a `Float16`, -a `Float32`, or a `Float64` depending on the length of the string `str` -(note that this length must hence be no greater than 16). """ hex2num(::Type{T}, s::AbstractString) where {T<:BitReal} = - reinterpret(T, parse(unsigned(T), s, 16)) + reinterpret(T, parse(reinterpret(Unsigned, T), s, 16)) const base36digits = ['0':'9';'a':'z'] const base62digits = ['0':'9';'A':'Z';'a':'z'] diff --git a/base/multinverses.jl b/base/multinverses.jl index be34348a1a17e1..88a07366510426 100644 --- a/base/multinverses.jl +++ b/base/multinverses.jl @@ -2,20 +2,10 @@ module MultiplicativeInverses -import Base: div, divrem, rem, unsigned +import Base: div, divrem, rem using Base: IndexLinear, IndexCartesian, tail export multiplicativeinverse -unsigned(::Type{Int8}) = UInt8 -unsigned(::Type{Int16}) = UInt16 -unsigned(::Type{Int32}) = UInt32 -unsigned(::Type{Int64}) = UInt64 -unsigned(::Type{Int128}) = UInt128 -unsigned(::Type{T}) where {T<:Unsigned} = T -unsigned(::Type{Float16}) = UInt16 -unsigned(::Type{Float32}) = UInt32 -unsigned(::Type{Float64}) = UInt64 - abstract type MultiplicativeInverse{T} end # Computes integer division by a constant using multiply, add, and bitshift. diff --git a/test/floatfuncs.jl b/test/floatfuncs.jl index 96ae477f0fdbd1..7523355095d772 100644 --- a/test/floatfuncs.jl +++ b/test/floatfuncs.jl @@ -41,7 +41,7 @@ for elty in (Float16,Float32,Float64), _ = 1:10 @test hex2num(num2hex(x)) ≈ x @test hex2num(elty, num2hex(x)) ≈ x end -@test_throws ArgumentError hex2num(String(rand('a':'f', rand(17:100)))) +@test_throws ArgumentError hex2num(String(rand(['a':'f';'0':'1'], rand(17:100)))) # round for elty in (Float32,Float64) diff --git a/test/int.jl b/test/int.jl index ad2e9a1e8f1f2e..71768f1616c29c 100644 --- a/test/int.jl +++ b/test/int.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license # Test integer conversion routines from int.jl - +using Base: BitInteger_types, BitFloat_types for y in (-4, Float32(-4), -4.0, big(-4.0)) @test flipsign(3, y) == -3 @@ -18,10 +18,10 @@ for y in (4, Float32(4), 4.0, big(4.0)) end # Result type must be type of first argument -for T in (Base.BitInteger_types..., BigInt, +for T in (BitInteger_types..., BigInt, Rational{Int}, Rational{BigInt}, Float16, Float32, Float64) - for U in (Base.BitInteger_types..., BigInt, + for U in (BitInteger_types..., BigInt, Rational{Int}, Rational{BigInt}, Float16, Float32, Float64) @test typeof(copysign(T(3), U(4))) === T @@ -124,7 +124,7 @@ for T in (UInt8, UInt16, UInt32, UInt64) end # Test bit shifts -for T in Base.BitInteger_types +for T in BitInteger_types nbits = 8*sizeof(T) issigned = typemin(T) < 0 highbit = T(2) ^ (nbits-1) @@ -203,7 +203,34 @@ end @test unsafe_trunc(Int8, -129) === Int8(127) # Test x % T returns a T -for T in [Base.BitInteger_types..., BigInt], - U in [Base.BitInteger_types..., BigInt] +for T in [BitInteger_types..., BigInt], + U in [BitInteger_types..., BigInt] @test typeof(rand(U(0):U(127)) % T) === T end + +@testset "reinterpret and unsigned/signed on $T" for T in BitInteger_types + t = -1 % T + A, B = T <: Unsigned ? (Unsigned, Signed) : (Signed, Unsigned) + @test reinterpret(A, reinterpret(B, t)) == t + @test reinterpret(A, t) == t + @test reinterpret(B, t) != t + @test (T <: Unsigned ? unsigned : signed)(T) === T + @test unsigned(T) <: Unsigned + @test signed(T) <: Signed +end + +@testset "unsigned/signed(::Bool)" begin + @test signed(true) === 1 + @test signed(false) === 0 + @test unsigned(true) === 1 % UInt + @test unsigned(false) === 0 % UInt + @test signed(Bool) === Int + @test unsigned(Bool) === UInt +end + +@testset "unsigned/signed(::$T)" for T in BitFloat_types + @test signed(T(1)) === Int(1) + @test unsigned(T(1)) === UInt(1) + @test_throws InexactError signed(T(1.1)) + @test_throws InexactError unsigned(T(1.1)) +end