Перестановки битов

28

Ваша цель состоит в том, чтобы создать функцию или программу для обращения битов в диапазоне целых чисел с заданным целым числом n . Другими словами, вы хотите найти перестановку перестановок битов в диапазоне 2 n элементов с нулевым индексом. Это также последовательность OEIS A030109 . Этот процесс часто используется при вычислении быстрых преобразований Фурье, таких как встроенный алгоритм Кули-Тьюки для БПФ. Существует также проблема для вычисления БПФ для последовательностей, где длина равна степени 2.

Этот процесс требует от вас итерации в диапазоне [0, 2 n -1] и преобразования каждого значения в двоичное и обращения битов в этом значении. Вы будете рассматривать каждое значение как n- значное число в базе 2, что означает, что обращение будет происходить только среди последних n битов.

Например, если n = 3, диапазон целых чисел равен [0, 1, 2, 3, 4, 5, 6, 7]. Эти

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

где каждый индекс i преобразуется в индекс j с использованием обращения битов. Это означает, что на выходе [0, 4, 2, 6, 1, 5, 3, 7].

Выходными данными для n от 0 до 4 являются

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

Возможно, вы заметили формирование шаблона. Учитывая n , вы можете взять предыдущую последовательность для n -1 и удвоить ее. Затем объедините этот двойной список с тем же двойным списком, но увеличенным на единицу. Показывать,

[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]

где представляет конкатенацию.

Вы можете использовать любой из двух методов выше, чтобы сформировать свое решение. Если вы знаете лучший способ, вы можете использовать его тоже. Любой метод хорош, если он выводит правильные результаты.

правила

  • Это поэтому выигрывает самое короткое решение.
  • Встроенные функции, которые решают эту проблему в целом, и встроенные средства, которые вычисляют обращение битов значения, не допускаются. Это не включает встроенные функции, которые выполняют двоичное преобразование или другие побитовые операции.
  • Ваше решение должно быть, по крайней мере, действительно для n от 0 до 31.
миль
источник
3
«Встроенные функции, которые решают эту проблему в целом, и встроенные средства, которые вычисляют обращение битов значения, не допускаются». Аууу IntegerReverse[Range[2^#]-1,2,#]&. (Я не знаю, зачем Mathematica нужна эта встроенная система, но я думаю, что это не намного страннее, чем Sunset...)
Мартин Эндер,
@MartinEnder Хорошая находка. Когда-нибудь может случиться так, что в Mathematica будет встроено все, в том числе генерирование случайных вызовов кода-гольфа.
миль
Можем ли мы печатать 0вместо [0]или это должен быть список?
Деннис
@ Денис Хорошая мысль. Я позволю это, поскольку важно, чтобы выходные данные представляли действительную перестановку независимо от формата.
миль
Будет ли возвращение false вместо 0 приемлемым?
Деннис

Ответы:

2

Желе , 7 6 байт

Ḥ;‘$$¡

Спасибо @EriktheOutgolfer за отыгрывание 1 байта!

Попробуйте онлайн!

Как это работает

Ḥ;‘$$¡  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.
Деннис
источник
4

05AB1E , 8 байтов

Код:

¾)IF·D>«

Объяснение:

¾         # 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.

Использует кодировку CP-1252 . Попробуйте онлайн! ,

Аднан
источник
Хороший! Бьет тот, который у меня был :)
Emigna
@ Emigna Спасибо! Какой была ваша версия тогда?
Аднан
0)ïsF·D>«было близко, хотя Были некоторые проблемы с «0».
Emigna
1
Хорошее использование ¾. Должен вспомнить этот трюк.
Эминья,
1
@KevinCruijssen Для ввода 0 выглядит красивее иметь представление int 0, а не представление строки :). Кроме этого, нет никаких различий.
Аднан
4

MATL, 13 12 10 9 8 байт

0i:"EtQh

Попробуйте онлайн

объяснение

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

Для полноты, вот мой старый ответ с использованием нерекурсивного подхода (9 байт).

W:qB2&PXB

Попробуйте онлайн

объяснение

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
источник
4

J, 15 11 байт

2&(*,1+*)0:

Существует альтернатива для 15 байтов, которая использует прямое двоичное преобразование и обращение.

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

использование

   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

объяснение

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
миль
источник
3

Октава, 37 байт

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

Создает анонимную функцию с именем, ansкоторую можно просто вызвать с помощью ans(n).

Демо онлайн

Suever
источник
3

Python 2, 56 55 54 байта

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

Проверьте это на Ideone .

Спасибо @xnor за вывод 1 байта!

Деннис
источник
Вы можете сделать [0][n:]or.
xnor
3

Java, 422 419 байт:

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())));}}

Что ж, я наконец-то выучил Java для моего второго языка программирования, поэтому я хотел использовать свои новые навыки для выполнения простого задания, и, хотя оно оказалось очень долгим, я не разочарован. Я просто рад, что смог выполнить простую задачу на Java.

Попробуйте онлайн! (Ideone)

Р. Кап
источник
Вы можете сэкономить несколько байтов, анализируя int из аргументов, вместо чтения из StdIn
Павел
3

Mathematica, 56 33 байта

Количество байтов предполагает кодированный источник ISO 8859-1.

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

При этом используется рекурсивное определение для определения унарного оператора ±.

Мартин Эндер
источник
3

Perl, 46 45 байт

Включает +1 для -p

Дайте номер ввода на STDIN

#!/usr/bin/perl -p
map$F[@F]=($_*=2)+1,@F for(@F=0)..$_;$_="@F"
Тон Хоспел
источник
2

Javascript ES6, 65 53 51 байт

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

Использует рекурсивный алгоритм двойного приращения-конкат.

Пример работы:

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
источник
Как насчет f=n=>n>0?(r=f(n-1).map(i=>i*2)).concat(r.map(i=>i+1)):[0]?
миль
@ Майлз Ой, не понял, мне не нужен базовый случай n==1, спасибо.
Дендробиум
2
Я думаю, что мне удалось сбрить 2 байта, переместив умножение на два:f=(n,m=1)=>n?[...n=f(n-1,m+m),...n.map(i=>i+m)]:[0]
Нил
2

Python 3, 67 59 байт

Спасибо @Dennis за -8 байт

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

Мы также можем иметь (модифицированную) прямую реализацию в Python, даже если это довольно долго.

Анонимная функция, которая принимает входные данные по аргументу и возвращает перевернутую битовую перестановку в виде списка.

Как это работает

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

Попробуйте это на Ideone

TheBikingViking
источник
2
Это связано с моим подходом, но игра в гольф не переживет порт на Python 3.
Деннис
2

Дьялог АПЛ , 12 байт

требует ⎕IO←0 по умолчанию во многих системах.

2⊥⊖2⊥⍣¯12*⎕

2⊥ из базы-2 из

перевернутый

2⊥⍣¯1 обратная от-базы-2

первые n целых чисел, где n является

2* 2 к власти

числовой ввод

Попробуй APL онлайн!


Для сравнения, вот другой метод:

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

( функциональный поезд ...

2∘× два раза (аргумент)

, соединенный с

1+ один плюс

2∘× два раза (аргумент)

)⍣ применяется столько раз, сколько указано

числовой ввод

на

0 нуль

Адам
источник
(⍋,⍨)⍣⎕⊢0( ⎕io←0)
ngn
@ngn Это никак не связано с моим алгоритмом.
Адам
я думал, что это было похоже на ваш "другой метод", но хорошо, я напишу отдельный ответ
ngn
2

K (нгн / к) , 11 8 байт

2/|!2|&:

Попробуйте онлайн!

 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

& последний глагол в композиции, поэтому нам нужно : чтобы заставить его быть монадическим

СПП
источник
1

Юлия, 23 года 22 байта

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

Скорее простая реализация процесса, описанного в спецификации спец.

Попробуйте онлайн!

Деннис
источник
1

Clojure, 78 байт

Просто следуя спецификации ...

(defn f[n](if(= n 0)[0](let[F(map #(* 2 %)(f(dec n)))](concat F(map inc F)))))
NikoNyrh
источник
1

Рубин, 57 байт:

->n{(0...a=2**n).map{|x|("%b"%x+=a).reverse[0,n].to_i 2}}
гигабайт
источник
1

PHP, 57 байт

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

принимает входные данные из параметра командной строки, печатает значения, разделенные подчеркиванием. Беги с -nr.

рекурсивное решение, 72 байта

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

функция принимает целое число, возвращает массив

Titus
источник
1

Perl 6 , 42 байта

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

Попробуйте онлайн!

Увеличение целого числа просто переворачивает последовательность младших битов, например, из xxxx0111в xxxx1000. Таким образом, следующий инвертированный по битам индекс можно получить из предыдущего, перевернув последовательность старших значащих битов. Маска XOR может быть вычислена с помощью m - (m >> (ctz(i) + 1))for m = 2**nилиm = 2**n-1 .

Perl 6 , 30 байт

my&f={$_&&(^2 X+(f($_-1)X*2))}

Попробуйте онлайн!

Рекурсивный подход.

nwellnhof
источник
1

JavaScript (Firefox 30-57), 48 байт

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

Порт @ Dennis ♦ Python 2 решение.

Нил
источник
ReferenceError: f не определено
l4m2
1

Japt , 14 13 байт

2pU Ǥw ú0U Í

Попробуйте онлайн!

Распаковано и как это работает

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

Простая реализация.

фонтанчик для питья
источник
Там на самом деле недокументированные ярлыки для n2:Í
Оливер
1

APL (Dyalog Classic) , 9 байтов

(⍋,⍨)⍣⎕⊢0

Попробуйте онлайн!

оцененный вклад

( )⍣⎕⊢0применять вещь во ( )много раз, начиная с0

,⍨ объединить текущий результат с самим собой

индексы сортировки по возрастанию

СПП
источник
0

x86, 31 байт

Принимает достаточно большие значения int[] bufferin eaxи n in ecxи возвращает буфер вeax .

Реализует алгоритм объединения, указанный в операторе вызова. Может быть возможно сохранить байты, увеличив указатели на 4 вместо прямого доступа к массиву, ноlea / movуже довольно короток (3 байта для 3 регистров и множитель).

.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
источник