Поменяйтесь битами со своими соседями


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: 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, используя ваше выражение. Все это связано с байтовыми сбережениями против C-ответа 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 .
Деннис

@ Денис: Да, у меня работает в Си, мой плохой. На самом деле я тестировал выражение в calc(aka apcalc), а не в C. Я думал, что все будет в порядке, так как мне не нужно усечение до 32-бит или дополнения до двух. Я не думал, что выражение выглядело правильно, поэтому я был готов поверить своим неправильным тестам. Но в любом случае мне нужен лучший REPL для разработки битхаков. Какие-либо предложения? (в идеале командная строка Linux, как bc -lили calc, но фактически выставляет int32_t/ uint32_tили что-то, а не расширенную точность.)
Питер Кордес

10

Функция С, 38

Бит-вертел:

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

Ideone.


Или для удовольствия:

С рекурсивная функция, 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;}

Ideone.


1
Умное преобразование выражения в xnor приводит к уменьшению этого значения до 32 байт в C. Я разместил его как отдельный ответ, так как это существенно другой подход.
Питер Кордес

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.

Этот трюк с перестановками очень хорош!
Луис Мендо

7

Pyth, 9 байт

iXjQ4S2)4

Попробуйте это в Pyth Compiler .

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

  jQ4      Convert the input (Q) to base 4.
 X   S2)   Translate [1, 2] to [2, 1].
i       4  COnvert from base 4 to integer.

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?
user81655

@ user81655 И я n/2тоже могу использовать ! Я не знаю, почему я не думал об этом раньше.
Нил

Я никогда не видел >>>... что это?
Тит

@ Титус Это похоже, >>>но это делает беззнаковый сдвиг. >>>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-one-mask в обратном направлении. (И противоположная терминология: младший бит - это бит 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-байтовый цикл с использованием loopinsn, но он имел наихудшее время выполнения 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

зш, 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х
x1
1
^
Икс
r` (.) (.)
$ 2 $ 1
1
Икс@
+ `@ Х
Икс@@
Икс*(@*)
$ 0,1
0 $

Тестирование. (Слегка изменено.)

Ну просто ради интереса: 7 байт

T`12`21

Принимает base-4 в качестве входа и выводит как base-4.

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


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

1
@ Денис Теперь у меня есть эти биты поменялись местами.
Дрянная Монахиня

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 к ответу xnor на Python . Вместо маскировки в обе стороны, маскируйте в одну сторону и комбинируйте.

Это компилируется в тот же 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 использует целочисленные типы произвольной точности вместо усечения до фиксированного верхнего предела.


@ Денис: Ага, да, спасибо. Я сделал это последнее изменение после тестирования и пропустил разницу в выводе 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.

Ungolfed

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

Три вилки.

Примечание

В официальном переводчике ^:_1можно заменить inv, сохранив 1 байт.

Однако ни один из онлайн-переводчиков не реализует это.



1

INTERCAL , 60 байтов

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

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

Работает для 16-разрядных целых чисел, при этом ввод / вывод выполняется в наиболее естественном формате для INTERCAL: входные данные представляют собой последовательность десятичных цифр, написанных на одном из нескольких естественных или составных языков, а выходные данные представлены «разделенными римскими цифрами».

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

С поддержкой 32-битных целых чисел:

INTERCAL , 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, но так как это INTERCAL, я также чувствую, что этого не может быть.


0

Mathematica, 44 байта

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

Тот же подход, что и в моем ответе на CJam: конвертировать в base-4, менять местами 1 и 2, конвертировать обратно. Он также использует трюк алефальфы, чтобы заменить FromDigitsна Foldоперацию, чтобы сохранить один байт.



0

J, 22 байта

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

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

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

   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.