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


28

Ваша мета - створити функцію або програму для перетворення бітів у діапазоні цілих чисел із заданим цілим числом n . Іншими словами, ви хочете знайти перестановку бітів для діапазону 2 n елементів, нульове індексування. Це також послідовність OEIS A030109 . Цей процес часто використовується для обчислення швидких перетворень Фур'є, таких як місцевий алгоритм Cooley-Tukey для FFT. Існує також завдання для обчислення FFT для послідовностей, де довжина є потужністю 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
"Вбудовані, які вирішують цю задачу в цілому, та вбудовані, які обчислюють біт-реверсування значення, не дозволені." Awww, IntegerReverse[Range[2^#]-1,2,#]&. (Я не знаю, чому Mathematica потребує цього вбудованого, але, мабуть, це не набагато дивніше, ніж Sunset...)
Мартін Ендер

@MartinEnder Приємна знахідка. Колись, можливо, що в Mathematica буде вбудовано все, включаючи генерування випадкових проблем із кодом-гольфу.
милі

Чи можемо ми друкувати 0замість цього [0]чи це повинен бути список?
Денніс

@Dennis Добрий момент. Я дозволю це, оскільки важливо лише, щоб вихід представляв собою дійсну перестановку незалежно від формату.
милі

Чи прийнятним буде повернення помилки замість 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 Дякую! Якою була ваша версія тоді?
Аднан

0)ïsF·D>«було близько, хоча. У мене виникли проблеми з "0".
Емінья

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

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

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.

Спробуйте в Інтернеті! (Ідеон)


Ви можете зберегти кілька байтів, які аналізують int з аргументів, а не читати з StdIn
Павло

3

Математика, 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]

Як щодо f=n=>n>0?(r=f(n-1).map(i=>i*2)).concat(r.map(i=>i+1)):[0]?
милі

@miles Whoops, не зрозумів, що мені не потрібен базовий випадок n==1, дякую.
Дендробіум

2
Я думаю, що мені вдалося відголити 2 байти, перемістивши множення на два:f=(n,m=1)=>n?[...n=f(n-1,m+m),...n.map(i=>i+m)]:[0]
Ніл

2

Пітон 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


2
Це пов'язано з моїм підходом, але гольфізм не переживе порт на Python 3.
Денніс

2

Діалог APL , 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

К (нг / к) , 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

Clojure, 78 байт

Тільки слідуючи специфікації ...

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

1

Ruby, 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;}

функція приймає ціле число, повертає масив



1

Perl 6 , 42 байти

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

Спробуйте в Інтернеті!

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

Perl 6 , 30 байт

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

Спробуйте в Інтернеті!

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


1

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

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

Порт рішення Denton ♦ 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[] bufferв eaxі n в 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......|
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.