Обміняйте біти з сусідами


26

Опис завдання

З огляду на ціле число, поміняйте своєю (2k – 1) -й та 2k -найменшими значущими бітами для всіх цілих чисел k> 0 . Це послідовність A057300 в OEIS.

(Вважається, що число має "нескінченно багато" провідних нулів. На практиці це просто означає попереджати один 0 біт до чисел непарної довжини.)

введіть тут опис зображення

Це , тому найкоротший код (у байтах) виграє.

Тестові справи

0 -> 0
1 -> 2
9 -> 6
85 -> 170
220 -> 236
1827 -> 2835
47525 -> 30298

5
Чи можемо ми вважати, що число відповідає як int для таких речей, як бітове зсув?
xnor

1
@xnor: Я думаю, що це консенсус / за замовчуванням / співтовариство (інакше відповіді в C тощо завжди будуть помилковими)? Так впевнено! :)
Лінн

@Lynn: C вимагає unsigned char array_of_bytes[1024]працювати так, як ви очікуєте (тобто бути бітовим полем з 1024 * CHAR_BITзаписами). Я думаю, що більшість відповідей, що підтримують введення довільної довжини, вважають CHAR_BITрівними, оскільки зміщення бітів між байтами громіздке. Таким чином, ви абсолютно можете поставити вимогу підтримувати kпевний постійний розмір, наприклад, 256 або щось, що є розумним для AES, а мови без 256-бітових цілочисельних типів повинні використовувати петлі. Це може змусити векторів SIMD варто розглянути відповідь на x86 asm: P
Пітер Кордес

2
Я обміняю @Geobits міні-бітами
оптимізатором

Відповіді:



20

Python 2, 26 байт

lambda n:2*n-3*(4**n/3&n/2)

Трохи хитрощі!

Скажіть, nмає форму ...ghfedcbaу двійковій формі . Тоді ми можемо розділити його на кожен інший шматочок як

n   = o + 2*e
n   = ...hgfedcba
o   = ...0g0e0c0a
2*e = ...h0f0d0b0

Потім результат перемикання бітів sможе бути виражений як s=2*o+e.

s   = 2*o + e
s   = ...ghefcdab
2*o = ...g0e0c0a0
e   = ...0h0f0d0b

Ми вважаємо за краще обчислити лише одне eі o, тому виражаємо o=n-2*eта підміняємо

s=2*(n-2*e)+e = 2*n-3*e

Отже, тепер залишається висловитись eз точки зору n. Число M=4**n/3має форму ...10101010101у двійковій формі , яка служить маскою для непарних цифр. Експонент nгарантує, що Mце досить довго. Беручи порозрядне andзначення n/2і це значення дає eза бажанням.

n/2     = ...hgfedcb
M       = ...1010101
n/2 & M = ...h0f0d0b = e

Натомість ми можемо висловити eчерез o e=(n-o)/2, що дає s=(n+o*3)/2, що економить байт завдяки оптимізації від xsot.

lambda n:n+(n&4**n/3)*3>>1

Прекрасне пояснення та приємна хитрість використовувати маску лише один раз, віднімаючи з n. Однак я віддаю перевагу протилежному умові іменування "непарних" проти "парних". LSB - це біт 0, що є рівним (навіть якщо це перший біт). У програмі SIMD, де перетасовки часто вибирають елементи з індексом, індекси рахуються від 0, тому нормально вважати низький елемент рівним елементом. наприклад[ 3 2 1 0 ]
Пітер Кордес

Я додав відповідь С, використовуючи ваше вираження. Пояснюється це вся заслуга на заощадження байтів та відповідь C Digital Digital Trauma.
Пітер Кордес

2
26:lambda n:n+(n&4**n/3)*3>>1
xsot

@PeterCordes Ваш код C працює для мене з gcc 4.8.3 та налаштуваннями за замовчуванням. f(x){return x+((x&~0U/3)*3)>>1;}повертає 1 для введення 2 .
Денніс

@Dennis: Так, працює для мене в С, моє погано. Я насправді випробовував вираз у calc(aka apcalc), а не насправді C. Я думав, що я все в порядку, оскільки мені не потрібно врізання в 32-бітний або два доповнення. Я не вважав, що вираз виглядає правильно, тому я був готовий повірити в свої неправильні тести. Але в будь-якому випадку, мені потрібна краща відповідь для розробки біт-хаків. Будь-які пропозиції? (в ідеалі командний рядок Linux, як-от bc -lабо calc, але фактично викриваючи int32_t/ uint32_tчи щось, не розширена точність.)
Пітер Кордес

10

C функція, 38

Біт-подвійність:

f(x){return(x&~0U/3*2)/2+(x&~0U/3)*2;}

Ідеон.


Або для задоволення від цього:

C рекурсивна функція, 43

Відповідно до формули OEIS ,a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

f(x){return x>3?4*f(x/4)+f(x%4):x%3?3-x:x;}

або

f(x){return x>3?4*f(x/4)+f(x%4):x%2*2+x/2;}

Ідеон.


1
Розумна трансформація виразу xnor зводить це до 32 байт в С. Я розмістив це як окрему відповідь, оскільки це суттєво інший підхід.
Пітер Кордес

8

CJam, 16 14 13 байт

ri4b4e!2=f=4b

Перевірте це тут.

Пояснення

ri  e# Read input and convert to integer.
4b  e# Get base-4 digits.
4e! e# Push all permutations of [0 1 2 3].
2=  e# Select the third one which happens to be [0 2 1 3].
f=  e# For each base-4 digit select the value at that position in the previous
    e# list, which swaps 1s and 2s.
4b  e# Convert back from base 4.

Цей трюк з перестановками дуже хороший!
Луїс Мендо


5

JavaScript (ES6), 32 30 байт

(n,m=0x55555555)=>n*2&~m|n/2&m

Працює лише до 1073741823 через обмеження цілих чисел JavaScript. 38 36 байт працює до 4294967295:

(n,m=0x55555555)=>(n*2&~m|n/2&m)>>>0

Редагувати: збережено 2 байти завдяки @ user81655.

51 байт працює до 4503599627370495:

n=>parseInt(n.toString(4).replace(/1|2/g,n=>3-n),4)

Може n<<1бути n*2?
користувач81655

@ user81655 І я n/2теж можу використовувати ! Я не знаю, чому я раніше про це не думав.
Ніл

Я ніколи не бачив >>>... що це?
Тіт

@Titus Це схоже, >>>але це робить непідписаний зсув. >>>0в основному перетворюється на 32-бітне ціле число, яке не підписується.
Ніл

5

x86 функція asm: 14 байт машинного коду

uint64_t версія: 24 байти

x86-64 Конвенція про виклик SysV ( xin edi), але цей же машинний код також буде працювати в 32-бітовому режимі. (Де leaзашифровуватиметься як lea eax, [edi + eax*2], що дає однакові результати ).

0000000000000040 <onemask_even>:
  40:   89 f8                   mov    eax,edi
  42:   25 55 55 55 55          and    eax,0x55555555
  47:   29 c7                   sub    edi,eax
  49:   d1 ef                   shr    edi,1
  4b:   8d 04 47                lea    eax,[rdi+rax*2]
  4e:   c3                      ret    
4f: <end>

0x4f - 0x40 = 14 байт

Це вихід компілятора від використання чудової маски xnor, колись ідея навпаки. (І протилежна термінологія: низький біт - це біт 0, що є парним, а не непарним.)

unsigned onemask_even(unsigned x) {
  unsigned emask = ~0U/3;
  unsigned e = (x & emask);
  return e*2 + ((x - e) >> 1);
}

Я не знайшов жодних удосконалень щодо того, що робить компілятор. Я, можливо, написав це як mov eax, 0x555.../ and eax, edi, але це така ж довжина.


Ця ж функція для 64-бітових цілих чисел займає 24 байти (див. Посилання godbolt). Я не бачу жодного способу коротшого, ніж 10-байтовий, movabs rax, 0x55...щоб генерувати маску в регістрі. ( divінструкція x86 незграбна, тому непідписаний поділ всіх одиниць на 3 не допомагає.)

Я придумав цикл для створення маски в rax, але це 10 байт (точно така ж довжина, як і mov imm64).

# since 0x55 has its low bit set, shifting it out the top of RAX will set CF
0000000000000000 <swap_bitpairs64>:
   0:   31 c0                   xor    eax,eax      ; old garbage in rax could end the loop early
0000000000000002 <swap_bitpairs64.loop>:
   2:   48 c1 e0 08             shl    rax,0x8
   6:   b0 55                   mov    al,0x55      ; set the low byte
   8:   73 f8                   jnc    2 <swap_bitpairs64.loop>  ; loop until CF is set
000000000000000a <swap_bitpairs64.rest_of_function_as_normal>:
 # 10 bytes, same as   mov  rax, 0x5555555555555555
 # rax = 0x5555...
   a:   48 21 f8                and    rax,rdi
   ...

Якби ми знали, що жоден з існуючих байтів не raxмає встановленого низького біта, ми могли б пропустити цей xor, і це буде 8 байт.

Попередня версія цієї відповіді мала 10- loopбайтну петлю за допомогою insn, але вона мала найгірший час виконання 0xFFFFFFFFFFFFFF08ітерацій, тому що я лише встановив cl.


5

Оазис , 17 байт (неконкурентоспроможний)

n4÷axxn4÷xxe+3120

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

Оазис - мова, розроблена Аднаном, яка спеціалізується на послідовностях.

В даний час ця мова може виконувати рекурсію і закриту форму.

Ми використовуємо цю формулу: a(4n+k) = 4a(n) + a(k), 0 <= k <= 3

Вказати базовий випадок просто: 3120кінець в кінці просто означає це a(0)=0, a(1)=2, a(2)=1, a(3)=3.

n4÷axxn4÷xxe+3120
                0  a(0) = 0
               2   a(1) = 2
              1    a(2) = 1
             3     a(3) = 3

n                  push n (input)
 4÷                integer-divide by 4
   a               a(n/4)
    xx             double twice; multiply by 4
                   now we have 4a(n/4)
      n            push n (input)
       4÷xx        integer-divide by 4 and then multiply by 4
                   since there is no modulo currently, n%4
                   is built as n-(n/4*4)
           e       we should have done a(n-(n/4*4)), but this
                   is a shortcut for a(n-x) where x is the top
                   of stack. Therefore, we now have a(n-n/4*4)
                   which is a(n%4).
            +      add.

4

MATL , 10 байт

BP2eP1ePXB

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

Модифікована версія для створення перших термінів послідовності ( OEIS A057300 ).

Пояснення

B     % Take input implicitly. Convert to binary array
P     % Flip
2e    % Convert to two-row 2D array, padding with a trailing zero if needed. 
      % Because of the previous flip, this really corresponds to a leading zero
P     % Flip each column. This corresponds to swapping the bits
1e    % Reshape into a row
P     % Flip, to undo the initial flipping
XB    % Convert from binary array to number. Display implicitly

3

zsh, 28 байт

<<<$[`tr 12 21<<<$[[#4]$1]`]

Приймає введення як аргумент командного рядка, виводить на STDOUT.

Це не сумісно з Bash, оскільки він використовує синтаксис базового перетворення, специфічний для zsh.

                       $1     input (first command line argument)
                 $[      ]    arithmetic expansion
                   [#4]       output in base 4
              <<<             pass the result of this to...
      tr                      the `tr' command
         12 21                and replace 1s with 2s, 2s with 1s
     `                    `   evaluate the result...
   $[                      ]  in another arithmetic expansion, to convert back
                                to base 10
<<<                           output the result on STDOUT

3

Сітківка, 70 байт

. +
$ *
+ `(1 +) \ 1
$ 1х
х1
1
^
х
r` (.) (.)
$ 2 $ 1
1
х @
+ `@ x
x @@
x * (@ *)
$ .1
0 $

Тестовий набір. (Трохи модифікований.)

Ну просто для розваги: ​​7 байт

T`12`21

Приймає base-4 як вхідний, а виводить як base-4.

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


4
Я конфліктний. Я хочу підняти нижню половину вашої відповіді, але знизити верхню половину.
Денніс

1
@Dennis Тепер я міняв ці біти.
Leaky Nun

3

05AB1E, 8 байт

4B12‡4ö

Дякуємо @Adnan за -5 байт!

Використовує кодування CP-1252.

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

Пояснення:

4B       - Take input and convert to base 4.
  12Â    - Push 12 bifurcated.
     ‡   - Transliterate [1, 2] to [2, 1].
      4ö - Convert to base 10.

2
Хороший, але ви можете замінити 1 2‚2 1‚з 12Â8 байт.
Аднан

Гарна відповідь! Ось 8-байтна альтернатива:4в2‰íJJC
Кевін Кройсейсен

3

C, 32 30 29 байт

f(x){return(x&~0U/3)*3+x>>1;}                // 30 bit version, see below

// less golfed:
f(x){return ((x & 0x55555555)*3 + x) >>1;}   //  >> is lower precedence than +

Алгоритм скопійовано з коментаря xsot на відповідь Pynor на xnor . Замість маскування обох способів маскуйте один спосіб і комбінуйте.

Це компілюється в той самий asm, що і остання тестована версія , і вона працює (для x до 0x3FFFFFFF, і для x вище, поки біт 30 не встановлено, див. Нижче). У машинному коді це така ж довжина, як у моєї існуючої відповіді ASM.


Наведена вище версія завжди очищає високий біт результату . Найкраща безпечна версія - 32 байти:

g(x){return 2*x-3*(x/2U&~0U/3);}   // safe 32bit version, works for all x

У версії Python цієї проблеми немає, оскільки python використовує цілі типи довільної точності при необхідності замість обрізання до фіксованої верхньої межі.


@Dennis: Argh, так, дякую. Я зробив останню зміну після тестування і пропустив різницю у виході ASM. Недарма я думав, що це виглядає неправильно; Я забув, що >>це такий низький пріоритет. Я не займаюся гольфом досить часто, щоб точно пам’ятати правила, оскільки попередження компілятора, які пропонують парени в небезпечних випадках, зберігають мене в реальному коді. : P
Пітер Кордес

2
Ви можете скинути цей простір, переставивши доданки у виразі.
xsot

2

Javascript (ES6), 113 109 байт

Збережено 4 байти завдяки Upgoat

n=>+('0b'+/(..)+$/.exec('0'+n.toString`2`)[0].split``.reduce((p,c)=>p.length-1?[p.join(c)]:[p[0],c],[''])[0],2)

Як це працює

n=>+('0b'+                              //parse as binary literal
    /(..)+$/.exec('0'+n.toString`2`)[0] //convert to binary string with an even number of digits
        .split``                        //convert to array
        .reduce((p,c)=>p.length-1?[p.join(c)]:[p[0],c],[''])
                                        //swap all numbers
)

використовувати +('0b"+binary_string_here)замість `parseInt (..., 2)
Downgoat

1

J, 20 байт

4#.0 2 1 3{~4#.^:_1]

Використання

>> f =: 4#.0 2 1 3{~4#.^:_1]
>> f 85
<< 170

Де >>STDIN і <<STDOUT.

Безумовно

to_base   =: 4 #.^:_1 ]
transpose =: 0 2 1 3 {~ to_base
from_base =: 4 #. transpose

Три виделки.

Sidenote

В офіційному перекладачі ^:_1може бути замінено inv, збереження 1 байт.

Однак жоден з онлайн-перекладачів цього не реалізує.



1

INTERCAL , 60 байт

DOWRITEIN.1PLEASE.1<-!1~#21845'$.1~#43690DOREADOUT.1DOGIVEUP

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

Працює для 16-бітових цілих чисел, введення-виведення зроблено в найбільш природному форматі для INTERCAL: вхід - це серія десяткових цифр, написаних однією з декількох природних або побудованих мов, а вихід - "римськими цифрами, що врізані".

Це одна з тих рідкісних проблем, коли бінарні оператори INTERCAL насправді можуть бути використані інтуїтивно, оскільки перестановка бітів - це те, чим вони займаються. Select ( ~) бере біти з першого аргументу, відповідного аргументам у другому аргументі, і прошиває їх праворуч з нулями та змішується ( ), і перемежовує їх назад у зворотному порядку. На щастя для підрахунку байтів, хоча оператори INTERCAL не мають визначеного пріоритету (оскільки мета мови - не мати прецедентів), виявляється, що C-INTERCAL у TIO не потребує великого групування для цього конкретного виразу, коштуючи лише один байт, оскільки можна скоротити .$ ) перемежовує біти з його аргументами, щоб біти першого аргументу були більш значущими. Тож прямим рішенням є виділення менш значущих бітів, що чергуються ( .1~#21845), виділення більш значущих бітів, що чергуються ().1~#43690'.!

З підтримкою 32-бітних цілих чисел:

ІНТЕРКАЛ , 67 байт

DOWRITEIN:1PLEASE:1<-':1~#0$#65535'$:1~#65535$#0DOREADOUT:1DOGIVEUP

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

INTERCAL не дозволяє 32-бітні літерали, що насправді робить це трохи простішим для читання, оскільки це означає, що магічні константи для вибору змінних бітів повинні бути побудовані шляхом змішування двох 16-бітних літералів разом, де один - всі нулі, а інший - всі. (Насправді, навіть якби були 32-бітні літерали, це все одно буде коротшим. #0$#65535Вимкнено два байти #1431655765, і те саме стосується іншого.) Це передає INTERCAL весь процес неприродно.

Альтернативний підхід із незграбним використанням перевантаження операндів :

INTERCAL , 71 байт

DO:1<-:1/.2$.3PLEASEWRITEIN:2DO:1<-:2PLEASE:2<-.3$.2DOREADOUT:2DOGIVEUP

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

Це позбавляє від вибору взагалі, оголосивши , що :1буде .2змішувався з .3, встановивши :1на вхід, а потім виводить .3змішаний з .2. Оскільки :1був перевантажений як .2$.3, DO :1 <- :2присвоює значення таким .2і .3таким, що :1набуває значення :2, що призводить до .2вміщення більш значущих чергуються бітів з :2і .3містять менш значущі біти, що чергуються. Це було б коротше двох 32-розрядних рішень на чотири байти, якби вони PLEASE WRITE IN :1могли замінити PLEASE WRITE IN :2 DO :1 <- :2перевантажені :1, алеCALCULATINGвиявляється необхідним для використання перевантаження. Я також відчуваю, що може бути якийсь коротший спосіб здійснити саму перевантаження, ніж запускати програму DO:1<-:1/.2$.3, але оскільки це ІНТЕРКАЛ, я також відчуваю, що не може бути.


0

Математика, 44 байти

Fold[3#+##&,#~IntegerDigits~4/.{1->2,2->1}]&

Той самий підхід, що і у моїй відповіді CJam: конвертувати в базу-4, поміняти 1 і 2, перетворити назад. Він також використовує трюк alephalpha для заміни FromDigitsз Foldроботи , щоб зберегти один байт.



0

J, 22 байти

([:,_2|.\,&0)&.(|.@#:)

Альтернативний підхід, заснований на маніпулюванні масивом замість трюку базового 4.

Використання

   f =: ([:,_2|.\,&0)&.(|.@#:)
   (,.f"0) 0 1 9 85 220 1827 47525
    0     0
    1     2
    9     6
   85   170
  220   236
 1827  2835
47525 30298

Пояснення

([:,_2|.\,&0)&.(|.@#:)  Input: n
                   #:   Get the value as a list of base 2 digits
                |.@     Reverse it
(           )&.         Apply to the list of base 2 digits
         ,&0            Append a zero to the end of the list
    _2  \               Split the list into nonoverlapping sublists of size 2
      |.                Reverse each sublist
 [:,                    Flatten the list of sublists into a list
             &.(    )   Apply the inverse of (reversed base 2 digits)
                        to convert back to a number and return it

0

REXX, 88 байт

n=x2b(d2x(arg(1)))
o=0
do while n>''
  parse var n a+1 b+1 n
  o=o||b||a
  end
say x2d(b2x(o))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.