Bit-Reversal Permutations

28

9

Your goal is to create a function or a program to reverse the bits in a range of integers given an integer n. In other words, you want to find the bit-reversal permutation of a range of 2n items, zero-indexed. This is also the OEIS sequence A030109. This process is often used in computing Fast Fourier Transforms, such as the in-place Cooley-Tukey algorithm for FFT. There is also a challenge for computing the FFT for sequences where the length is a power of 2.

This process requires you to iterate over the range [0, 2n-1] and to convert each value to binary and reverse the bits in that value. You will be treating each value as a n-digit number in base 2 which means reversal will only occur among the last n bits.

For example, if n = 3, the range of integers is [0, 1, 2, 3, 4, 5, 6, 7]. These are

i  Regular  Bit-Reversed  j
0    000        000       0
1    001        100       4
2    010        010       2
3    011        110       6
4    100        001       1
5    101        101       5
6    110        011       3
7    111        111       7

where each index i is converted to an index j using bit-reversal. This means that the output is [0, 4, 2, 6, 1, 5, 3, 7].

The output for n from 0 thru 4 are

n    Bit-Reversed Permutation
0    [0]
1    [0, 1]
2    [0, 2, 1, 3]
3    [0, 4, 2, 6, 1, 5, 3, 7]

You may have noticed a pattern forming. Given n, you can take the previous sequence for n-1 and double it. Then concatenate that doubled list to the same double list but incremented by one. To show,

[0, 2, 1, 3] * 2 = [0, 4, 2, 6]
[0, 4, 2, 6] + 1 = [1, 5, 3, 7]
[0, 4, 2, 6] ⊕ [1, 5, 3, 7] = [0, 4, 2, 6, 1, 5, 3, 7]

where represents concatenation.

You can use either of the two methods above in order to form your solution. If you know a better way, you are free to use that too. Any method is fine as long as it outputs the correct results.

Rules

  • This is so the shortest solution wins.
  • Builtins that solve this challenge as a whole and builtins that compute the bit-reversal of a value are not allowed. This does not include builtins which perform binary conversion or other bitwise operations.
  • Your solution must be, at the least, valid for n from 0 to 31.

miles

Posted 2016-06-20T19:32:55.020

Reputation: 15 654

3"Builtins that solve this challenge as a whole and builtins that compute the bit-reversal of a value are not allowed." Awww, IntegerReverse[Range[2^#]-1,2,#]&. (I don't know why Mathematica needs that built-in but I guess it's not a lot weirder than Sunset...) – Martin Ender – 2016-06-20T20:47:29.850

@MartinEnder Nice find. Someday, it might be that there will be a builtin for everything in Mathematica, including generating random code-golf challenges. – miles – 2016-06-20T20:57:29.177

Can we print 0 instead of [0] or does it have to be a list? – Dennis – 2016-06-20T21:03:01.460

@Dennis Good point. I'll allow it, since it's only important that the output represents a valid permutation regardless of format. – miles – 2016-06-20T21:10:06.900

Would returning false instead of 0 be acceptable?

– Dennis – 2016-06-20T21:21:24.207

Yes, as long as your language interprets false as 0 and true as 1. – miles – 2016-06-20T22:28:38.090

Answers

2

Jelly, 7 6 bytes

Ḥ;‘$$¡

Thanks to @EriktheOutgolfer for golfing off 1 byte!

Try it online!

How it works

Ḥ;‘$$¡  Main link. No arguments.
        Implicit argument / initial return value: 0

     ¡  Read an integer n from STDIN and call the link to the left n times.
    $   Combine the two links to the left into a monadic chain, to be called
        with argument A (initially 0, later an array).
Ḥ         Unhalve; yield 2A.
   $      Combine the two links to the left into a monadic chain, to be called
          with argument 2A.
  ‘         Increment; yield 2A + 1
 ;          Concatenate 2A and 2A + 1.

Dennis

Posted 2016-06-20T19:32:55.020

Reputation: 196 637

5

Haskell, 40 37 bytes

f 0=[0]
f a=[(*2),(+1).(*2)]<*>f(a-1)

Try it online!

Thanks to @Laikoni for three bytes!

Angs

Posted 2016-06-20T19:32:55.020

Reputation: 4 825

4

Jelly, 5 bytes

2ṗ’UḄ

Try it online!

-1 thanks to Dennis.

Erik the Outgolfer

Posted 2016-06-20T19:32:55.020

Reputation: 38 134

4

05AB1E, 8 bytes

Code:

¾)IF·D>«

Explanation:

¾         # Constant for 0.
 )        # Wrap it up into an array.
  IF      # Do the following input times.
    ·     # Double every element.
     D    # Duplicate it.
      >   # Increment by 1.
       «  # Concatenate the first array.

Uses the CP-1252 encoding. Try it online!.

Adnan

Posted 2016-06-20T19:32:55.020

Reputation: 41 965

Nice one! Beats the one I had :) – Emigna – 2016-06-20T19:44:16.370

@Emigna Thanks! What was your version then? – Adnan – 2016-06-20T19:45:07.990

0)ïsF·D>« was close though. Had some issues with the '0'. – Emigna – 2016-06-20T19:48:54.720

@Emigna Oh, I actually have that same issue now. Lemme fix that :p – Adnan – 2016-06-20T19:51:47.843

1Nice usage of ¾. Gonna have to remember that trick. – Emigna – 2016-06-20T19:53:45.723

@Emigna I know it's been almost two years, but (out of curiosity) what were the issues of 0) vs ¾)? The test case in the TIO seems to work in both cases. – Kevin Cruijssen – 2018-05-25T12:31:28.157

1@KevinCruijssen For input 0, it looks prettier to have the int representation of 0 and not the string representation :). Other than that, there are no differences. – Adnan – 2018-05-25T12:40:57.440

@Adnan Ah ok, it was only a visual difference with [0, ... vs ['0', ...? – Kevin Cruijssen – 2018-05-25T12:48:43.097

@KevinCruijssen Yes, that is correct – Adnan – 2018-05-25T18:19:12.163

4

J, 15 11 bytes

2&(*,1+*)0:

There is an alternative for 15 bytes that uses straight-forward binary conversion and reversal.

2|."1&.#:@i.@^]

Usage

   f =: 2&(*,1+*)0:
   f 0
0
   f 1
0 1
   f 2
0 2 1 3
   f 3
0 4 2 6 1 5 3 7
   f 4
0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15

Explanation

2&(*,1+*)0:  Input: n
         0:  The constant 0
2&(     )    Repeat n times starting with x = [0]
2      *       Multiply each in x by 2
     1+        Add 1 to each
    ,          Append that to
2  *           The list formed by multiplying each in x by 2
               Return that as the next value of x
             Return the final value of x

miles

Posted 2016-06-20T19:32:55.020

Reputation: 15 654

4

MATL, 13 12 10 9 8 bytes

0i:"EtQh

Try it Online

Explanation

0       % Push number literal 0 to the stack
i:"     % Loop n times
    E   % Multiply by two
    t   % Duplicate
    Q   % Add one
    h   % Horizontally concatenate the result
        % Implicit end of loop, and implicitly display the result

For the sake of completeness, here was my old answer using the non-recursive approach (9 bytes).

W:qB2&PXB

Try it Online

Explanation

W       % Compute 2 to the power% ofImplicitly thegrab input (n) and compute 2^n
:       % Create an array from [1...2^n]
q       % Subtract 1 to get [0...(2^n - 1)]
B       % Convert to binary where each row is the binary representation of a number
2&P     % Flip this 2D array of binary numbers along the second dimension
XB      % Convert binary back to decimal
        % Implicitly display the result

Suever

Posted 2016-06-20T19:32:55.020

Reputation: 10 257

3

Octave, 37 bytes

@(n)bin2dec(fliplr(dec2bin(0:2^n-1)))

Creates an anonymous function named ans that can simply be called with ans(n).

Online Demo

Suever

Posted 2016-06-20T19:32:55.020

Reputation: 10 257

3

Mathematica, 56 33 bytes

Byte count assumes an ISO 8859-1 encoded source.

±0={0};±x_:=Join[y=±(x-1)2,y+1]

This uses the recursive definition to define a unary operator ±.

Martin Ender

Posted 2016-06-20T19:32:55.020

Reputation: 184 808

3

Python 2, 56 55 54 bytes

f=lambda n:[0][n:]or[i+j*2for i in 0,1for j in f(n-1)]

Test it on Ideone.

Thanks to @xnor for golfing off 1 byte!

Dennis

Posted 2016-06-20T19:32:55.020

Reputation: 196 637

You can do [0][n:]or. – xnor – 2016-06-21T01:47:26.530

3

Java, 422 419 bytes:

import java.util.*;class A{static int[]P(int n){int[]U=new int[(int)Math.pow(2,n)];for(int i=0;i<U.length;i++){String Q=new String(Integer.toBinaryString(i));if(Q.length()<n){Q=new String(new char[n-Q.length()]).replace("\0","0")+Q;}U[i]=Integer.parseInt(new StringBuilder(Q).reverse().toString(),2);}return U;}public static void main(String[]a){System.out.print(Arrays.toString(P(new Scanner(System.in).nextInt())));}}

Well, I finally learned Java for my second programming language, so I wanted to use my new skills to complete a simple challenge, and although it turned out very long, I am not disappointed. I am just glad I was able to complete a simple challenge in Java.

Try It Online! (Ideone)

R. Kap

Posted 2016-06-20T19:32:55.020

Reputation: 4 730

You can save a few bytes parsing an int from args rather than reading from StdIn – Pavel – 2017-01-05T00:06:40.377

3

Perl, 46 45 bytes

Includes +1 for -p

Give input number on STDIN

#!/usr/bin/perl -p
map$F[@F]=($_*=2)+1,@F for(@F=0)..$_;$_="@F"

Ton Hospel

Posted 2016-06-20T19:32:55.020

Reputation: 14 114

2

Dyalog APL, 12 bytes

Requires ⎕IO←0 which is default on many systems.

2⊥⊖2⊥⍣¯1⍳2*⎕

2⊥ from-base-2 of

the flipped

2⊥⍣¯1 inverse of from-base-2 of

the first n integers, where n is

2* 2 to the power of

numeric input

TryAPL online!


For comparison, here is the other method:

(2∘×,1+2∘×)⍣⎕⊢0

( the function train...

2∘× two times (the argument)

, concatenated to

1+ one plus

2∘× two times (the argument)

)⍣ applied as many times as specified by

numeric input

on

0 zero

Adám

Posted 2016-06-20T19:32:55.020

Reputation: 37 779

(⍋,⍨)⍣⎕⊢0 (⎕io←0) – ngn – 2019-04-25T16:49:59.270

@ngn That has nothing to do with my algorithm. – Adám – 2019-04-27T21:25:14.283

i thought it was similar to your "other method" but ok, i'll write a separate answer – ngn – 2019-04-27T21:56:49.433

2

Ruby, 51 bytes

f=->n{n<1?[0]:(a=f[n-1].map{|i|i*2})+a.map(&:next)}

Try it online!

Asone Tuhid

Posted 2016-06-20T19:32:55.020

Reputation: 1 944

2

K (ngn/k), 11 8 bytes

2/|!2|&:

Try it online!

 x:3  / just for testing
 &x   / that many zeroes
0 0 0
 2|&x / max with 2
2 2 2
 !x#2 / binary words of length x, as a transposed matrix
(0 0 0 0 1 1 1 1
 0 0 1 1 0 0 1 1
 0 1 0 1 0 1 0 1)
 |!x#2 / reverse
(0 1 0 1 0 1 0 1
 0 0 1 1 0 0 1 1
 0 0 0 0 1 1 1 1)
 2/|!x#2 / base-2 decode the columns
0 4 2 6 1 5 3 7

& is the last verb in the composition so we need a : to force it to be monadic

ngn

Posted 2016-06-20T19:32:55.020

Reputation: 11 449

2

Pyth - 11 bytes

ushMByMGQ]0

Test Suite.

Maltysen

Posted 2016-06-20T19:32:55.020

Reputation: 25 023

2

Javascript ES6, 65 53 51 bytes

f=(n,m=1)=>n?[...n=f(n-1,m+m),...n.map(i=>i+m)]:[0]

Uses the recursive double-increment-concat algorithm.

Example runs:

f(0) => [0]
f(1) => [0, 1]
f(2) => [0, 2, 1, 3]
f(4) => [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]

Dendrobium

Posted 2016-06-20T19:32:55.020

Reputation: 2 412

How about f=n=>n>0?(r=f(n-1).map(i=>i*2)).concat(r.map(i=>i+1)):[0]? – miles – 2016-06-20T20:37:05.427

@miles Whoops, didn't realize I don't need a base case for n==1, thanks. – Dendrobium – 2016-06-20T20:43:42.017

2I think I managed to shave off 2 bytes by moving the multiplication by two: f=(n,m=1)=>n?[...n=f(n-1,m+m),...n.map(i=>i+m)]:[0] – Neil – 2016-06-20T23:30:16.630

2

Python 3, 67 59 bytes

Thanks to @Dennis for -8 bytes

lambda n:[int(bin(i+2**n)[:1:-1],2)//2for i in range(2**n)]

We may as well have a (modified) straightforward implementation in Python, even if this is quite long.

An anonymous function that takes input by argument and returns the bit-reversed permutation as a list.

How it works

lambda n                 Anonymous function with input n
...for i in range(2**n)  Range from 0 to 2**n-1
bin(i+2**n)[:1:-1]       Convert i+2**n to binary string, giving 1 more digit than needed,
                         remove '0b' from start, and reverse
int(...,2)               Convert back to decimal
...//2                   The binary representation of the decimal value has one trailing
                         bit that is not required. This is removed by integer division by 2
:[...]                   Return as list

Try it on Ideone

TheBikingViking

Posted 2016-06-20T19:32:55.020

Reputation: 3 674

2This ties with my approach, but it golfiness won't survive a port to Python 3. – Dennis – 2016-06-21T00:07:52.027

1

Clojure, 78 bytes

Just following the spec...

(defn f[n](if(= n 0)[0](let[F(map #(* 2 %)(f(dec n)))](concat F(map inc F)))))

NikoNyrh

Posted 2016-06-20T19:32:55.020

Reputation: 2 361

1

Ruby, 57 47 39 bytes

->n{[*0...2**n].sort_by{|a|a.digits 2}}

Try it online!

3 years later, 18 bytes golfed.

G B

Posted 2016-06-20T19:32:55.020

Reputation: 11 099

1

PHP, 57 bytes

while($i<1<<$argv[1])echo bindec(strrev(decbin($i++))),_;

takes input from command line parameter, prints underscore-delimited values. Run with -nr.

recursive solution, 72 bytes

function p($n){$r=[$n];if($n)foreach($r=p($n-1)as$q)$r[]=$q+1;return$r;}

function takes integer, returns array

Titus

Posted 2016-06-20T19:32:55.020

Reputation: 13 814

1

Perl 6, 25 bytes

{[X+] 0,|(0 X(2 X**^$_))}

Try it online!

Perl 6, 42 bytes

{0,{$^p+^($_-$_/2+>lsb ++$)}...$_}o 1+<*-1

Try it online!

Incrementing an integer simply flips a sequence of least-significant bits, for example from xxxx0111 to xxxx1000. So the next bit-reversed index can be obtained from the previous one by flipping a sequence of most-significant bits. The XOR mask can be computed with m - (m >> (ctz(i) + 1)) for m = 2**n or m = 2**n-1.

nwellnhof

Posted 2016-06-20T19:32:55.020

Reputation: 10 037

1

Japt, 14 13 bytes

2pU Ǥw ú0U Í

Try it online!

Unpacked & How it works

2pU o_s2 w ú0U n2

2pU    2**n
o_     range(2**n).map(...)
s2       convert to binary string
w        reverse
ú0U      right-pad to length n, filling with '0'
n2       convert binary string to number

Straightforward implementation.

Bubbler

Posted 2016-06-20T19:32:55.020

Reputation: 16 616

There's actually an undocumented shortcut for n2: Í – Oliver – 2018-05-25T15:35:37.653

1

APL (Dyalog Classic), 9 bytes

(⍋,⍨)⍣⎕⊢0

Try it online!

evaluated input

( )⍣⎕⊢0 apply the thing in ( ) that many times, starting with 0

,⍨ concatenate the current result with itself

indices of a sort-ascending permutation

ngn

Posted 2016-06-20T19:32:55.020

Reputation: 11 449

1

Julia, 23 22 bytes

!n=n>0&&[t=2*!~-n;t+1]

Rather straightforward implementation of the process described in the challenge spec.

Try it online!

Dennis

Posted 2016-06-20T19:32:55.020

Reputation: 196 637

1

JavaScript (Firefox 30-57), 48 bytes

f=n=>n?[for(x of[0,1])for(y of f(n-1))x+y+y]:[0]

Port of @Dennis♦'s Python 2 solution.

Neil

Posted 2016-06-20T19:32:55.020

Reputation: 95 035

ReferenceError: f is not defined – l4m2 – 2018-05-25T10:39:44.690

1

Pyth, 8 bytes

iR2_M^U2

Try it online: Demonstration or Test Suite

Explanation:

iR2_M^U2Q   implicit Q (=input number) at the end
     ^U2Q   generate all lists of zeros and ones of length Q in order
   _M       reverse each list
iR2         convert each list to a number

Jakube

Posted 2016-06-20T19:32:55.020

Reputation: 21 462

0

x86, 31 bytes

Takes a sufficiently large int[] buffer in eax and n in ecx, and returns the buffer in eax.

Implements the concatenating algorithm given in the challenge statement. It may be possible to save bytes by incrementing the pointers by 4 instead of using array accesses directly, but lea/mov is already pretty short (3 bytes for 3 regs and a multiplier).

.section .text
.globl main
main:
        mov     $buf, %eax          # buf addr
        mov     $3, %ecx            # n 

start:
        xor     %ebx, %ebx
        mov     %ebx, (%eax)        # init buf[0] = 0 
        inc     %ebx                # x = 1

l1:
        mov     %ebx, %edi          
        dec     %edi                # i = x-1
        lea     (%eax,%ebx,4), %edx # buf+x 

l2:
        mov     (%eax,%edi,4), %esi # z = buf[i]
        sal     %esi                # z *= 2
        mov     %esi, (%eax,%edi,4) # buf[i] = z
        inc     %esi                # z += 1
        mov     %esi, (%edx,%edi,4) # buf[x+i] = z

        dec     %edi                # --i 
        jns     l2                  # do while (i >= 0)

        sal     %ebx                # x *= 2
        loop    l1                  # do while (--n)

        ret

.data
buf:    .space 256, -1

Hexdump:

00000507  31 db 89 18 43 89 df 4f  8d 14 98 8b 34 b8 d1 e6  |1...C..O....4...|
00000517  89 34 b8 46 89 34 ba 4f  79 f1 d1 e3 e2 e7 c3     |.4.F.4.Oy......|

qwr

Posted 2016-06-20T19:32:55.020

Reputation: 8 929

0

TI-BASIC, 26 bytes

Input A:{0:For(I,1,A:2Ans:augment(Ans,1+Ans:End:Ans

Prompts the user to input n.

Outputs the bit-reversal permutation as is specified in the challenge.

Explanation:

Input A                  ;prompt the user for "n".  store the input into A
{0                       ;leave {0} in Ans
For(I,1,A                ;loop A times
2Ans                     ;double Ans and leave the result in Ans
augment(Ans,1+Ans        ;add 1 to Ans and append it to the previous result
                         ;  leave the new result in Ans 
End                      ;loop end
Ans                      ;leave Ans in Ans
                         ;implicit print of Ans

Examples:

prgmCDGF25

?1
           {0 1}
prgmCDGF25

?3
{0 4 2 6 1 5 3 7}

Note: TI-BASIC is a tokenized language. Character count does not equal byte count.

Tau

Posted 2016-06-20T19:32:55.020

Reputation: 1 935