From 1f52ab6405154d5f1f757e5dafedf53c72ac7fc4 Mon Sep 17 00:00:00 2001 From: Keno Fischer Date: Fri, 27 Jul 2018 00:10:18 -0400 Subject: [PATCH] Deprecate nextpow2/prevpow2 Base 2 is an important special case here, but we can just handle that as a special case in the implementation of `nextpow` rather than having a whole separate user facing function. --- NEWS.md | 2 ++ base/deprecated.jl | 4 +++ base/exports.jl | 2 -- base/gmp.jl | 7 +++--- base/intfuncs.jl | 53 ++++++++++----------------------------- doc/src/base/math.md | 2 -- stdlib/Random/src/misc.jl | 4 +-- test/intfuncs.jl | 3 +-- test/numbers.jl | 23 +++++++++-------- 9 files changed, 38 insertions(+), 62 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5a8463a19c962..e97f4ed9e8b36 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1352,6 +1352,8 @@ Deprecated or removed * `sortrows`/`sortcols` have been deprecated in favor of the more general `sortslices`. + * `nextpow2`/`prevpow2` have been deprecated in favor of the more general `nextpow`/`prevpow` functions. + Command-line option changes --------------------------- diff --git a/base/deprecated.jl b/base/deprecated.jl index 49306b88c763c..9309fe962354d 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1780,6 +1780,10 @@ end @deprecate sortrows(A::AbstractMatrix; kws...) sortslices(A, dims=1, kws...) @deprecate sortcols(A::AbstractMatrix; kws...) sortslices(A, dims=2, kws...) +# PR #28304 +@deprecate nextpow2(x) nextpow(2, x) +@deprecate prevpow2(x) prevpow(2, x) + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/exports.jl b/base/exports.jl index b684eaf9eca49..73e11eb65ddec 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -297,7 +297,6 @@ export muladd, nextfloat, nextpow, - nextpow2, nextprod, numerator, one, @@ -305,7 +304,6 @@ export powermod, prevfloat, prevpow, - prevpow2, rad2deg, rationalize, real, diff --git a/base/gmp.jl b/base/gmp.jl index 2063fd9328e60..d80182646732e 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -8,7 +8,7 @@ import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, binomial, cmp, convert, div, divrem, factorial, fld, gcd, gcdx, lcm, mod, ndigits, promote_rule, rem, show, isqrt, string, powermod, sum, trailing_zeros, trailing_ones, count_ones, tryparse_internal, - bin, oct, dec, hex, isequal, invmod, prevpow2, nextpow2, ndigits0zpb, + bin, oct, dec, hex, isequal, invmod, _prevpow2, _nextpow2, ndigits0zpb, widen, signed, unsafe_trunc, trunc, iszero, isone, big, flipsign, signbit, hastypemax @@ -634,10 +634,11 @@ function ndigits0zpb(x::BigInt, b::Integer) end end +# Fast paths for nextpow(2, x::BigInt) # below, ONE is always left-shifted by at least one digit, so a new BigInt is # allocated, which can be safely mutated -prevpow2(x::BigInt) = -2 <= x <= 2 ? x : flipsign!(ONE << (ndigits(x, base=2) - 1), x) -nextpow2(x::BigInt) = count_ones_abs(x) <= 1 ? x : flipsign!(ONE << ndigits(x, base=2), x) +_prevpow2(x::BigInt) = -2 <= x <= 2 ? x : flipsign!(ONE << (ndigits(x, base=2) - 1), x) +_nextpow2(x::BigInt) = count_ones_abs(x) <= 1 ? x : flipsign!(ONE << ndigits(x, base=2), x) Base.checked_abs(x::BigInt) = abs(x) Base.checked_neg(x::BigInt) = -x diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 87f412f661aab..c3ec78eeb31e9 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -292,7 +292,7 @@ function powermod(x::Integer, p::Integer, m::T) where T<:Integer (m == 1 || m == -1) && return zero(m) b = oftype(m,mod(x,m)) # this also checks for divide by zero - t = prevpow2(p) + t = prevpow(2, p) r::T = 1 while true if p >= t @@ -309,43 +309,10 @@ end # optimization: promote the modulus m to BigInt only once (cf. widemul in generic powermod above) powermod(x::Integer, p::Integer, m::Union{Int128,UInt128}) = oftype(m, powermod(x, p, big(m))) -# smallest power of 2 >= x - -""" - nextpow2(n::Integer) - -The smallest power of two not less than `n`. Returns 0 for `n==0`, and returns -`-nextpow2(-n)` for negative arguments. - -# Examples -```jldoctest -julia> nextpow2(16) -16 - -julia> nextpow2(17) -32 -``` -""" -nextpow2(x::Unsigned) = oneunit(x)<<((sizeof(x)<<3)-leading_zeros(x-oneunit(x))) -nextpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -nextpow2(unsigned(-x)) : nextpow2(unsigned(x))) - -""" - prevpow2(n::Integer) - -The largest power of two not greater than `n`. Returns 0 for `n==0`, and returns -`-prevpow2(-n)` for negative arguments. - -# Examples -```jldoctest -julia> prevpow2(5) -4 - -julia> prevpow2(0) -0 -``` -""" -prevpow2(x::Unsigned) = one(x) << unsigned((sizeof(x)<<3)-leading_zeros(x)-1) -prevpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -prevpow2(unsigned(-x)) : prevpow2(unsigned(x))) +_nextpow2(x::Unsigned) = oneunit(x)<<((sizeof(x)<<3)-leading_zeros(x-oneunit(x))) +_nextpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -_nextpow2(unsigned(-x)) : _nextpow2(unsigned(x))) +_prevpow2(x::Unsigned) = one(x) << unsigned((sizeof(x)<<3)-leading_zeros(x)-1) +_prevpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -_prevpow2(unsigned(-x)) : _prevpow2(unsigned(x))) """ ispow2(n::Integer) -> Bool @@ -387,8 +354,12 @@ julia> nextpow(4, 16) See also [`prevpow`](@ref). """ function nextpow(a::Real, x::Real) - a <= 1 && throw(DomainError(a, "`a` must be greater than 1.")) x <= 0 && throw(DomainError(x, "`x` must be positive.")) + # Special case fast path for x::Integer, a == 2. + # This is a very common case. Constant prop will make sure that a call site + # specified as `nextpow(2, x)` will get this special case inlined. + a == 2 && isa(x, Integer) && return _nextpow2(x) + a <= 1 && throw(DomainError(a, "`a` must be greater than 1.")) x <= 1 && return one(a) n = ceil(Integer,log(a, x)) p = a^(n-1) @@ -419,8 +390,10 @@ julia> prevpow(4, 16) See also [`nextpow`](@ref). """ function prevpow(a::Real, x::Real) - a <= 1 && throw(DomainError(a, "`a` must be greater than 1.")) x < 1 && throw(DomainError(x, "`x` must be ≥ 1.")) + # See comment in nextpos() for a == special case. + a == 2 && isa(x, Integer) && return _prevpow2(x) + a <= 1 && throw(DomainError(a, "`a` must be greater than 1.")) n = floor(Integer,log(a, x)) p = a^(n+1) p <= x ? p : a^n diff --git a/doc/src/base/math.md b/doc/src/base/math.md index 0fa973df3c828..57c1b5e674a9c 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -165,8 +165,6 @@ Base.gcd Base.lcm Base.gcdx Base.ispow2 -Base.nextpow2 -Base.prevpow2 Base.nextpow Base.prevpow Base.nextprod diff --git a/stdlib/Random/src/misc.jl b/stdlib/Random/src/misc.jl index e2356f12b8d98..0e7bb9782e500 100644 --- a/stdlib/Random/src/misc.jl +++ b/stdlib/Random/src/misc.jl @@ -145,7 +145,7 @@ randsubseq(A::AbstractArray, p::Real) = randsubseq(GLOBAL_RNG, A, p) ## rand Less Than Masked 52 bits (helper function) "Return a sampler generating a random `Int` (masked with `mask`) in ``[0, n)``, when `n <= 2^52`." -ltm52(n::Int, mask::Int=nextpow2(n)-1) = LessThan(n-1, Masked(mask, UInt52Raw(Int))) +ltm52(n::Int, mask::Int=nextpow(2, n)-1) = LessThan(n-1, Masked(mask, UInt52Raw(Int))) ## shuffle & shuffle! @@ -183,7 +183,7 @@ function shuffle!(r::AbstractRNG, a::AbstractArray) @assert !has_offset_axes(a) n = length(a) @assert n <= Int64(2)^52 - mask = nextpow2(n) - 1 + mask = nextpow(2, n) - 1 for i = n:-1:2 (mask >> 1) == i && (mask >>= 1) j = 1 + rand(r, ltm52(i, mask)) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index c96776f2f7498..4ead5b224fad0 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -89,14 +89,13 @@ end @test powermod(2, -2, -5) == -1 end @testset "nextpow/prevpow" begin - @test nextpow2(3) == 4 @test nextpow(2, 3) == 4 @test nextpow(2, 4) == 4 @test nextpow(2, 7) == 8 @test_throws DomainError nextpow(0, 3) @test_throws DomainError nextpow(3, 0) - @test prevpow2(3) == 2 + @test prevpow(2, 3) == 2 @test prevpow(2, 4) == 4 @test prevpow(2, 5) == 4 @test_throws DomainError prevpow(0, 3) diff --git a/test/numbers.jl b/test/numbers.jl index 3bed5952746c0..421616d1a096b 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -1909,20 +1909,21 @@ end @test rem(typemin(Int),-1) == 0 @test mod(typemin(Int),-1) == 0 end -@testset "prevpow2/nextpow2" begin - @test nextpow2(0) == prevpow2(0) == 0 - for i = -2:2 - @test nextpow2(i) == prevpow2(i) == i +@testset "prevpow(2, _)/nextpow(2, _)" begin + for i = 1:2 + @test nextpow(2, i) == prevpow(2, i) == i end - @test nextpow2(56789) == -nextpow2(-56789) == 65536 - @test prevpow2(56789) == -prevpow2(-56789) == 32768 - for i = -100:100 - @test nextpow2(i) == nextpow2(big(i)) - @test prevpow2(i) == prevpow2(big(i)) + @test nextpow(2, 56789) == 65536 + @test_throws DomainError nextpow(2, -56789) + @test prevpow(2, 56789) == 32768 + @test_throws DomainError prevpow(2, -56789) + for i = 1:100 + @test nextpow(2, i) == nextpow(2, big(i)) + @test prevpow(2, i) == prevpow(2, big(i)) end for T in (Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64) - @test nextpow2(T(42)) === T(64) - @test prevpow2(T(42)) === T(32) + @test nextpow(2, T(42)) === T(64) + @test prevpow(2, T(42)) === T(32) end end @testset "ispow2" begin