From fb301f424d2b15818557e5634879b874d7e0558e Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 20 Feb 2020 11:33:08 -0800 Subject: [PATCH] add `bitreverse` function (#34791) --- NEWS.md | 1 + base/bitarray.jl | 16 +++------------- base/exports.jl | 1 + base/int.jl | 34 ++++++++++++++++++++++++++++++++++ test/int.jl | 11 +++++++++++ 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/NEWS.md b/NEWS.md index d097474a91629..097320a65bfc9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -53,6 +53,7 @@ New library functions * Add function `ismutable` and deprecate `isimmutable` to check whether something is mutable.([#34652]) * `include` now accepts an optional `mapexpr` first argument to transform the parsed expressions before they are evaluated ([#34595]). +* New function `bitreverse` for reversing the order of bits in a fixed-width integer ([#34791]). New library features -------------------- diff --git a/base/bitarray.jl b/base/bitarray.jl index 7c98256bc2017..2bbb138c1d7e5 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1187,16 +1187,6 @@ function reverse(A::BitArray; dims::Integer) return B end -function reverse_bits(src::UInt64) - z = src - z = ((z >>> 1) & 0x5555555555555555) | ((z << 1) & 0xaaaaaaaaaaaaaaaa) - z = ((z >>> 2) & 0x3333333333333333) | ((z << 2) & 0xcccccccccccccccc) - z = ((z >>> 4) & 0x0f0f0f0f0f0f0f0f) | ((z << 4) & 0xf0f0f0f0f0f0f0f0) - z = ((z >>> 8) & 0x00ff00ff00ff00ff) | ((z << 8) & 0xff00ff00ff00ff00) - z = ((z >>> 16) & 0x0000ffff0000ffff) | ((z << 16) & 0xffff0000ffff0000) - return ((z >>> 32) & 0x00000000ffffffff) | ((z << 32) & 0xffffffff00000000) -end - function reverse!(B::BitVector) # Basic idea: each chunk is divided into two blocks of size k = n % 64, and # h = 64 - k. Walk from either end (with indices i and j) reversing chunks @@ -1220,14 +1210,14 @@ function reverse!(B::BitVector) i, j = 0, length(B.chunks) u = UInt64(0) - v = reverse_bits(B.chunks[j]) + v = bitreverse(B.chunks[j]) B.chunks[j] = 0 @inbounds while true i += 1 if i == j break end - u = reverse_bits(B.chunks[i]) + u = bitreverse(B.chunks[i]) B.chunks[i] = 0 B.chunks[j] |= u >>> h B.chunks[i] |= v >>> h @@ -1236,7 +1226,7 @@ function reverse!(B::BitVector) if i == j break end - v = reverse_bits(B.chunks[j]) + v = bitreverse(B.chunks[j]) B.chunks[j] = 0 B.chunks[i] |= v << k B.chunks[j] |= u << k diff --git a/base/exports.jl b/base/exports.jl index 6362bc2316598..e5346c56701a9 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -220,6 +220,7 @@ export atanh, big, binomial, + bitreverse, bswap, cbrt, ceil, diff --git a/base/int.jl b/base/int.jl index 668879656ab09..ea6fbe58563a9 100644 --- a/base/int.jl +++ b/base/int.jl @@ -860,3 +860,37 @@ for op in (:+, :-, :*, :&, :|, :xor) return $op(aT, bT) end end + +const _mask1_uint128 = (UInt128(0x5555555555555555) << 64) | UInt128(0x5555555555555555) +const _mask2_uint128 = (UInt128(0x3333333333333333) << 64) | UInt128(0x3333333333333333) +const _mask4_uint128 = (UInt128(0x0f0f0f0f0f0f0f0f) << 64) | UInt128(0x0f0f0f0f0f0f0f0f) + +""" + bitreverse(x) + +Reverse the order of bits in integer `x`. `x` must have a fixed bit width, +e.g. be an `Int16` or `Int32`. + +!!! compat "Julia 1.5" + This function requires Julia 1.5 or later. + +# Examples +```jldoctest +julia> bitreverse(0x8080808080808080) +0x0101010101010101 + +julia> reverse(bitstring(0xa06e)) == bitstring(bitreverse(0xa06e)) +true +``` +""" +function bitreverse(x::BitInteger) + # TODO: consider using llvm.bitreverse intrinsic + z = unsigned(x) + mask1 = _mask1_uint128 % typeof(z) + mask2 = _mask2_uint128 % typeof(z) + mask4 = _mask4_uint128 % typeof(z) + z = ((z & mask1) << 1) | ((z >> 1) & mask1) + z = ((z & mask2) << 2) | ((z >> 2) & mask2) + z = ((z & mask4) << 4) | ((z >> 4) & mask4) + return bswap(z) % typeof(x) +end diff --git a/test/int.jl b/test/int.jl index 9f8dbefd9984a..383849b221d2d 100644 --- a/test/int.jl +++ b/test/int.jl @@ -352,3 +352,14 @@ end end end end + +@testset "bitreverse" begin + for T in Base.BitInteger_types + x = rand(T)::T + @test bitreverse(x) isa T + @test reverse(bitstring(x)) == bitstring(bitreverse(x)) + end + @test bitreverse(0x80) === 0x01 + @test bitreverse(Int64(456618293)) === Int64(-6012608040035942400) + @test bitreverse(Int32(456618293)) === Int32(-1399919400) +end