Skip to content

Commit

Permalink
add bitreverse function (#34791)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson authored Feb 20, 2020
1 parent 6a9a926 commit fb301f4
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 13 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------------------
Expand Down
16 changes: 3 additions & 13 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ export
atanh,
big,
binomial,
bitreverse,
bswap,
cbrt,
ceil,
Expand Down
34 changes: 34 additions & 0 deletions base/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 11 additions & 0 deletions test/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit fb301f4

Please sign in to comment.