diff --git a/base/deprecated.jl b/base/deprecated.jl index 66d4af48e4cf8..2a1b1088566f1 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1350,6 +1350,25 @@ end @deprecate srand(filename::AbstractString, n::Integer=4) srand(read!(filename, Array{UInt32}(Int(n)))) @deprecate MersenneTwister(filename::AbstractString) srand(MersenneTwister(0), read!(filename, Array{UInt32}(Int(4)))) +# PR #22203 +@deprecate num2hex(n::Union{Bool, Base.BitReal}) bits(n, hex) + +""" + 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) + depwarn("hex2num(s) is deprecated, use reinterpret(T::Type, s)", :hex2num) + l = length(s) + l > 16 && throw(ArgumentError("the length of the passed string must be <= 16, got $l")) + reinterpret(l <= 4 ? Float16 : l <= 8 ? Float32 : Float64, s) +end +export hex2num + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index a3f2530e4fef3..994dc185744c9 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -76,21 +76,6 @@ Subtraction operator. """ -(x, y) -""" - bits(n) - -A string giving the literal bit representation of a number. - -```jldoctest -julia> bits(4) -"0000000000000000000000000000000000000000000000000000000000000100" - -julia> bits(2.2) -"0100000000000001100110011001100110011001100110011001100110011010" -``` -""" -bits - """ getindex(type[, elements...]) @@ -565,18 +550,6 @@ original string, otherwise they must be from distinct character ranges. """ eachmatch -""" - num2hex(f) - -Get a hexadecimal string of the binary representation of a floating point number. - -```jldoctest -julia> num2hex(2.2) -"400199999999999a" -``` -""" -num2hex - """ truncate(file,n) @@ -1121,13 +1094,6 @@ julia> bin(bswap(1)) """ bswap -""" - maxintfloat(T) - -The largest integer losslessly representable by the given floating-point DataType `T`. -""" -maxintfloat - """ delete!(collection, key) @@ -1360,13 +1326,6 @@ false """ isempty -""" - hex2num(str) - -Convert a hexadecimal string to the floating point number it represents. -""" -hex2num - """ InexactError() @@ -2165,14 +2124,6 @@ Values for `String` can be of that type, or `Vector{UInt8}`. """ isvalid(T,value) -""" - unsigned(x) -> Unsigned - -Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as -unsigned without checking for negative values. -""" -unsigned - """ reverseind(v, i) @@ -2297,14 +2248,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 6e06e23302d1d..c02a3a75c0ffd 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -138,7 +138,46 @@ convert(::Type{T}, x::T) where {T<:Tuple{Any,Vararg{Any}}} = x oftype(x,c) = convert(typeof(x),c) +""" + unsigned(x) -> Unsigned + +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). + +```jldoctest +julia> unsigned(12) +0x000000000000000c + +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). + +```jldoctest +julia> signed(0xc) +12 + +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/exports.jl b/base/exports.jl index b9bd9ecebe427..a76072fc17984 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -340,7 +340,6 @@ export gamma, gcd, gcdx, - hex2num, hypot, imag, inv, @@ -378,7 +377,6 @@ export nextpow2, nextprod, numerator, - num2hex, one, oneunit, powermod, diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index a5973c7d99986..904f9088336e9 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -16,6 +16,11 @@ signbit(x::Float64) = signbit(bitcast(Int64, x)) signbit(x::Float32) = signbit(bitcast(Int32, x)) signbit(x::Float16) = signbit(bitcast(Int16, x)) +""" + maxintfloat(T) + +The largest integer losslessly representable by the given floating-point DataType `T`. +""" maxintfloat(::Type{Float64}) = 9007199254740992. maxintfloat(::Type{Float32}) = Float32(16777216.) maxintfloat(::Type{Float16}) = Float16(2048f0) @@ -24,20 +29,6 @@ maxintfloat() = maxintfloat(Float64) isinteger(x::AbstractFloat) = (x - trunc(x) == 0) -num2hex(x::Float16) = hex(bitcast(UInt16, x), 4) -num2hex(x::Float32) = hex(bitcast(UInt32, x), 8) -num2hex(x::Float64) = hex(bitcast(UInt64, x), 16) - -function hex2num(s::AbstractString) - if length(s) <= 4 - return bitcast(Float16, parse(UInt16, s, 16)) - end - if length(s) <= 8 - return bitcast(Float32, parse(UInt32, s, 16)) - end - return bitcast(Float64, parse(UInt64, s, 16)) -end - """ round([T,] x, [digits, [base]], [r::RoundingMode]) diff --git a/base/int.jl b/base/int.jl index 19b65d5ea8f94..3eaede6288e58 100644 --- a/base/int.jl +++ b/base/int.jl @@ -23,6 +23,51 @@ const BitInteger = Union{BitInteger_types...} const BitSigned64T = Union{Type{Int8}, Type{Int16}, Type{Int32}, Type{Int64}} const BitUnsigned64T = Union{Type{UInt8}, Type{UInt16}, Type{UInt32}, Type{UInt64}} +const BitFloat_types = (Float16, Float32, Float64) +const BitFloat = Union{BitFloat_types...} +const BitReal_types = (BitInteger_types..., BitFloat_types...) +const BitReal = Union{BitReal_types...} + +## integer signed-ness conversions + +reinterpret(::Type{Unsigned}, x::BitInteger) = unsigned(x) +reinterpret(::Type{ Signed}, x::BitInteger) = signed(x) +reinterpret(::Type{Unsigned}, ::Type{Bool}) = UInt8 +reinterpret(::Type{ Signed}, ::Type{Bool}) = Int8 +reinterpret(::Type{Unsigned}, x::Bool) = x % UInt8 +reinterpret(::Type{ Signed}, x::Bool) = x % Int8 +reinterpret(::Type{Unsigned}, ::Type{Char}) = UInt32 +reinterpret(::Type{ Signed}, ::Type{Char}) = Int32 +reinterpret(::Type{Unsigned}, x::Char) = unsigned(x) +reinterpret(::Type{ Signed}, x::Char) = signed(x) + +""" + unsigned(T::Type) -> UnsignedType + +Return the return-type of `unsigned(x::T)`, so that `unsigned(x)::unsigned(typeof(x))`. + +```jldoctest +julia> unsigned(Int64) +UInt64 +``` +""" +unsigned(::Type{T}) where {T<:Unsigned} = T + +""" + signed(T::Type) -> SignedType + +Return the return-type of `signed(x::T)`, so that `signed(x)::signed(typeof(x))`. + +```jldoctest +julia> signed(UInt64) +Int64 +``` +""" +signed(::Type{T}) where {T<:Signed} = T + +unsigned(::Type{<:Union{Bool,BitFloat}}) = UInt +signed( ::Type{<:Union{Bool,BitFloat}}) = Int + ## integer comparisons ## (<)(x::T, y::T) where {T<:BitSigned} = slt_int(x, y) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 50bb11bd47f59..ae73562b08a4b 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -1,5 +1,25 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# this construction is not available when put in int.jl and 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 + ## number-theoretic functions ## """ @@ -483,7 +503,22 @@ function hex(x::Unsigned, pad::Int, neg::Bool) String(a) end -num2hex(n::Integer) = hex(n, sizeof(n)*2) +""" + reinterpret(T::Type, str::AbstractString, b=16) + +Interprets a string as the bit representation of a +number of type `T`, encoded in base `b`. + +```jldoctest +julia> reinterpret(Float64, "400199999999999a") +2.2 + +julia> reinterpret(Int32, "fffffffe") +-2 +``` +""" +reinterpret(::Type{T}, s::AbstractString, b=16) where {T<:Union{Bool,Char,BitReal}} = + reinterpret(T, parse(reinterpret(Unsigned, T), s, b)) const base36digits = ['0':'9';'a':'z'] const base62digits = ['0':'9';'A':'Z';'a':'z'] @@ -573,11 +608,30 @@ Convert an integer to a decimal string, optionally specifying a number of digits """ dec -bits(x::Union{Bool,Int8,UInt8}) = bin(reinterpret(UInt8,x),8) -bits(x::Union{Int16,UInt16,Float16}) = bin(reinterpret(UInt16,x),16) -bits(x::Union{Char,Int32,UInt32,Float32}) = bin(reinterpret(UInt32,x),32) -bits(x::Union{Int64,UInt64,Float64}) = bin(reinterpret(UInt64,x),64) -bits(x::Union{Int128,UInt128}) = bin(reinterpret(UInt128,x),128) +""" + bits(n, fmt=bin) + +A string giving the literal bit representation of a number. +The `fmt` function, which can be `bin` or `hex`, +determines the format used to represent those bits +respectively as a binary or hexadecimal string. + +```jldoctest +julia> bits(4) +"0000000000000000000000000000000000000000000000000000000000000100" + +julia> bits(4, hex) +"0000000000000004" + +julia> bits(2.2) +"0100000000000001100110011001100110011001100110011001100110011010" + +julia> bits(2.2, hex) +"400199999999999a" +``` +""" +bits(n::Union{Bool,Char,BitReal}, fmt::Union{typeof(bin), typeof(hex)}=bin) = + fmt(reinterpret(Unsigned, n), sizeof(n)*(fmt === bin ? 8 : 2)) """ digits([T<:Integer], n::Integer, base::T=10, pad::Integer=1) diff --git a/base/multinverses.jl b/base/multinverses.jl index 5b60e76e40a29..88a0736651042 100644 --- a/base/multinverses.jl +++ b/base/multinverses.jl @@ -2,17 +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{T<:Unsigned}(::Type{T}) = T - abstract type MultiplicativeInverse{T} end # Computes integer division by a constant using multiply, add, and bitshift. diff --git a/doc/src/stdlib/numbers.md b/doc/src/stdlib/numbers.md index af00def34e64e..2c3d44920a8c9 100644 --- a/doc/src/stdlib/numbers.md +++ b/doc/src/stdlib/numbers.md @@ -58,8 +58,6 @@ Base.Math.significand Base.Math.exponent Base.complex(::Complex) Base.bswap -Base.num2hex -Base.hex2num Base.hex2bytes Base.bytes2hex ``` diff --git a/test/floatfuncs.jl b/test/floatfuncs.jl index e246e8df5cac6..e46a1c797c469 100644 --- a/test/floatfuncs.jl +++ b/test/floatfuncs.jl @@ -35,10 +35,10 @@ for elty in (Float16,Float32,Float64) @test !isinteger(elty(NaN)) end -# num2hex, hex2num +# bits, reinterpret for elty in (Float16,Float32,Float64), _ = 1:10 x = rand(elty) - @test hex2num(num2hex(x)) ≈ x + @test reinterpret(elty, bits(x, hex)) ≈ x end # round diff --git a/test/int.jl b/test/int.jl index 4108960fc6fc7..f902d10a4f4b9 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, except for Bool -for U in (Base.BitInteger_types..., BigInt, +for U in (BitInteger_types..., BigInt, Rational{Int}, Rational{BigInt}, Float16, Float32, Float64) - for T in (Base.BitInteger_types..., BigInt, + for T in (BitInteger_types..., BigInt, Rational{Int}, Rational{BigInt}, Float16, Float32, Float64) @test typeof(copysign(T(3), U(4))) === T @@ -139,7 +139,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) @@ -218,7 +218,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 diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 0c6fc028a11c8..815a773849816 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -123,7 +123,15 @@ end @test hex(12) == "c" @test hex(-12, 3) == "-00c" -@test num2hex(1243) == (Int == Int32 ? "000004db" : "00000000000004db") +@test bits(1243, hex) == (Int == Int32 ? "000004db" : "00000000000004db") +@test bits(-1243, hex) == (Int == Int32 ? "fffffb25" : "fffffffffffffb25") +@test bits(true, hex) == "01" +@test bits(false, hex) == "00" + +for elty in Base.BitInteger_types, _ = 1:10 + x = rand(elty) + @test reinterpret(elty, bits(x, hex)) == x +end @test base(2, 5, 7) == "0000101" diff --git a/test/numbers.jl b/test/numbers.jl index 24fcb24a1864a..d9735e2935241 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -386,19 +386,19 @@ end @test base(12,typemin(Int128)) == "-2a695925806818735399a37a20a31b3534a8" @test base(12,typemax(Int128)) == "2a695925806818735399a37a20a31b3534a7" -@test hex2num("3ff0000000000000") == 1. -@test hex2num("bff0000000000000") == -1. -@test hex2num("4000000000000000") == 2. -@test hex2num("7ff0000000000000") == Inf -@test hex2num("fff0000000000000") == -Inf -@test isnan(hex2num("7ff8000000000000")) -@test isnan(hex2num("fff8000000000000")) -@test hex2num("3f800000") == 1.0f0 -@test hex2num("bf800000") == -1.0f0 -@test hex2num("7f800000") == Inf32 -@test hex2num("ff800000") == -Inf32 -@test isnan(hex2num("7fc00000")) -@test isnan(hex2num("ffc00000")) +@test reinterpret(Float64, "3ff0000000000000") == 1. +@test reinterpret(Float64, "bff0000000000000") == -1. +@test reinterpret(Float64, "4000000000000000") == 2. +@test reinterpret(Float64, "7ff0000000000000") == Inf +@test reinterpret(Float64, "fff0000000000000") == -Inf +@test isnan(reinterpret(Float64, "7ff8000000000000")) +@test isnan(reinterpret(Float64, "fff8000000000000")) +@test reinterpret(Float32, "3f800000") == 1.0f0 +@test reinterpret(Float32, "bf800000") == -1.0f0 +@test reinterpret(Float32, "7f800000") == Inf32 +@test reinterpret(Float32, "ff800000") == -Inf32 +@test isnan(reinterpret(Float32, "7fc00000")) +@test isnan(reinterpret(Float32, "ffc00000")) # floating-point printing @test repr(1.0) == "1.0"