Неразумные битовые операции

16

Мне нравится играть в гольф dc, но я иногда расстраиваюсь, потому что dcу меня нет побитовых операций.

Вызов

Обеспечить четыре названные функции , которые реализуют эквивалент операций с поразрядными &, |, ~и^ (побитовое AND, OR, NOT и XOR). Каждая функция принимает два операнда ( ~занимает только один), которые представляют собой как минимум 32-разрядные целые числа без знака. Каждая функция будет возвращать целое число без знака той же битовой ширины, что и операнды.

ограничение

Вы можете использовать только те операции, которые поддерживаются dc. Эти:

  • + - * / Арифметическое сложение, вычитание, умножение и деление
  • ~ по модулю (или divmod, если ваш язык поддерживает это)
  • ^ экспоненцирование
  • | модульное возведение в степень
  • v квадратный корень
  • > >= == != <= < стандартные операторы равенства / неравенства
  • >> << операторы сдвига битов. dcне имеет их, но так как они тривиально реализуются с точки зрения деления / умножения на степени 2, тогда я позволю это.

Управляющие структуры в dc могут быть неуклюже построены с использованием (рекурсивных) макросов и (в) операций равенства. Вы можете использовать любые встроенные управляющие структуры вашего языка.

Вы также можете использовать логические операторы && || ! , даже если они не доступны напрямую в dc.

Вы не должны использовать операторы побитового & , |, ~и ^или любые функции , которые реализуют их тривиальными.

Кроме того, вы не должны использовать встроенные операторы или функции базового преобразования строк.


Также рассмотрите возможность предоставления тестовой программы или фрагмента онлайн-компилятора (не включенного в счет по гольфу), чтобы подтвердить свой ответ.

Цифровая травма
источник
Можем ли мы реализовать одну функцию, которая принимает желаемую операцию в качестве параметра? Кроме того, можем ли мы разделить целое число на 2 в качестве замены для сдвига битов?
xnor
@xnor Вы должны предоставить 4 открытых функции, которые реализуют каждый из четырех операторов. У вас также могут быть общие / вспомогательные частные методы / функции, которые вызываются всеми четырьмя открытыми функциями, но все они должны быть включены в оценку игры в гольф.
Цифровая травма
7
@xnor Вы и только вы должны также реализовать оператор xnor ;-)
Digital Trauma
Могу ли я создать список из четырех анонимных функций?
xnor
@MariaTidalTug Какая эффективная разница между возвратом списка из четырех функций и ручным выбором и применением одной (как предложено xnor) по сравнению с наличием одной функции, которая принимает параметр выбора и выполняет сам выбор (как ответил Вольфхаммер)? Похоже, что они оба одинаково подрывают смысл наличия четырех именованных функций, поскольку они переносят размер кода в код пользователя. Я бы даже сказал, что первое подрывает его больше, поскольку пользовательский код, вероятно, более сложен в этом случае, чем во втором.
Runer112

Ответы:

4

С, 134

Препроцессор C довольно забавный, чтобы злоупотреблять. В основном этот макрос определяет 3 функции, a, o, и x, для and, orи xorсоответственно. Единственным отличием в алгоритме этих операций являются критерии установки бита в результате.

notэто функция n.

#define f(n,c)n(a,b){for(r=0,i=31;i+1;--i)if(((a>>i)%2+(b>>i)%2)c)r+=1<<i;return r;}
i,r;n(a){return 0xffffffff-a;}f(a,/2)f(o,)f(x,%2)

Программа тестирования (занимает много времени, я вообще не тратила время на ее оптимизацию, но она тестирует все возможные тесты, кроме связанных с MAX_INT):

#define m_assert(expected, condition, actual)\
    if(!((expected) condition (actual)))\
        printf("assert fail @ line %i, expected: %x, actual %x, condition "#condition"\n", __LINE__, expected, actual);

int main()  {
    unsigned int j,k;
    for(j=0; j<0xffff; ++j)    {
        m_assert(~j, ==, n(j));
        for(k=0; k<0xffff; ++k)    {
            m_assert(j & k, ==, a(j,k));
            m_assert(j | k, ==, o(j,k));
            m_assert(j ^ k, ==, x(j,k));
        }
    }
pseudonym117
источник
1
упс. забыл об этом. исправил это сейчас.
псевдоним117
4

ised 76 байт

ised также не имеет побитовых операций - обычно это раздражает, но теперь приветствуется, потому что нам действительно нужно их реализовать.

Функции будут храниться в пронумерованных слотах памяти (без подробных имен).

Преобразование в двоичный код и из него:

@5{:x/2^[32]%2:};
@6{:x@:2^[32]:};

НЕ может быть, @1{:$6::{1-$5::x}:}но, очевидно, проще просто вычесть:

@1{:2^32-x-1:};

ИЛИ:

@2{:$6::{$5::{x_0}:+$5::{x_1}>0}:};

И:

@3{:$6::{$5::{x_0}:*$5::{x_1}}:};

XOR:

@4{:$6::{$5::{x_0}:<>$5::{x_1}}:};

Это приведет нас к 156 байтам (с символами новой строки и точкой с запятой). Тестовый код будет просто (NOT, OR, AND, XOR подряд, найден под именами $ 1, $ 2, $ 3, $ 4):

> $1::{6}
4294967289
> $2::{12 11}
15
> $3::{12 11}
8
> $4::{12 11}
7

Но, конечно, ИЛИ и НЕ - это все, что нам действительно нужно, и все можно упростить:

@1{:2^32-x-1:};
@2{:@+{2^U{?{$5::x}%32}}:};
@3{:${1 2 1}::x:};
@4{:$3::{$2::x${1 2}::x}:};
@5{:x/2^[32]%2:};

Это 109 символов. Когда пропускаются символы новой строки и точки с запятой, и мы немного больше играем в гольф, у нас 76 символов:

@3{@1{:2^32-x-1:}@2{:@+{2^U{?{x/2^[32]%2}%32}}:}$1}@4{{:$2::x${1 2}::x:}$3};
Орион
источник
1

Ним (537) (490)

Nim Compiler 0.10.2

Я искал причину, чтобы научиться Ним, так что поехали.

Для кода гольф, я использовал переменные параметры и неявные доходы. Переменные параметры, согласно документации , менее эффективны в стеке. Лично мне труднее читать неявные возвраты и, вероятно, использовать их только в тривиальных процедурах.

Что касается алгоритмов, они достаточно просты. Для всех операций, кроме NOT, мы сравниваем каждый бит и вручную сравниваем их с нашей ожидаемой таблицей истинности. Установите каждый бит по мере необходимости в нашей выходной переменной. В Nim результатом является неявное возвращаемое значение.

Я не был уверен, разрешили ли нам использовать встроенные OR и AND для утверждения двух логических условий, поэтому вместо них была создана процедура notZero.

proc s(x, y, b: var int)=
  x = x div 2
  y = y div 2
  b *= 2

proc n(x: var int): int =
  return -(x+1)

proc a(x, y: var int): int =
  var b = 1
  while x > 0 and y > 0:
    if (x mod 2  + y mod 2) == 2:
      result += b

    s(x,y,b)

proc o(x, y: var int): int =
  var b = 1
  while x + y > 0:
    if (x mod 2 + y mod 2) >= 1:
      result += b

    s(x,y,b)

proc r(x, y: var int): int =
  var b = 1
  while x + y > 0:
    if (x mod 2 + y mod 2) == 1:
      result += b

    s(x,y,b)

Все еще ищу лучший метод ...

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

cory.todd
источник
@MariaTidalTug спасибо за разъяснения!
cory.todd
Я не могу воспроизвести это. Ваш калькулятор в режиме base-16?
cory.todd
Я добавил тестовый ремень, похожий на псевдоним117.
cory.todd
1

CJam, 71 байт

{:F;0{:R;2md@2md@+F~!2I#*R+}64fI\;\;}:B{"2-"B}:A{'!B}:O{0SB}:N{'(B}:X];

объяснение

"B : UInt64 UInt64 String -> UInt64
 Computes a bitwise operation on the two given unsigned integers. The operation
 is defined by the logical inverse of the result of evaluating the given string
 given the sum of two input bits.";
{
  :F;             "Save the operation string.";
  0               "Initialize the result to 0.";
  {               "For I from 0 through 63:";
    :R;             "Save the result.";
    2md@2md@        "Divide each input by 2 and collect the remainders as the
                     next pair of bits to process.";
    +F~!            "Compute the logical inverse of the result of evaluating
                     the operation string given the sum of the two bits.";
    2I#*            "Adjust the resulting bit to be in the correct output
                     position by multiplying it by 2^I.";
    R+              "Add the location-adjusted bit to the result.";
  }64fI
  \;\;            "Clean up.";
}:B

"A : UInt64 UInt64 -> UInt64
 Computes the bitwise AND of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !((bit_in_1 + bit_in_2) - 2)";
{"2-"B}:A

"O : UInt64 UInt64 -> UInt64
 Computes the bitwise OR of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !(!(bit_in_1 + bit_in_2))";
{'!B}:O

"N : UInt64 -> UInt64
 Computes the bitwise NOT of the given unsigned integer.
 This is done by passing the input and 0 along to B with an operation such that:
   bit_out = !((bit_in + 0))";
{0SB}:N

"X : UInt64 UInt64 -> UInt64
 Computes the bitwise XOR of the two given unsigned integers.
 This is done by passing the inputs along to B with an operation such that:
   bit_out = !((bit_in_1 + bit_in_2) - 1)";
{'(B}:X

];              "Clean up.";

Тестирование

Этот код проверяет выполнение каждой из функций my и, or, not и xor 100 раз с равномерно распределенными 64-разрядными входами без знака и сравнивает результат с результатом, полученным встроенным оператором. Из-за необоснованного использования оператора eval, он довольно медленный и может занять около минуты у онлайн-переводчика. Но если все идет хорошо, выполнение должно заканчиваться без вывода, потому что все найденные расхождения печатаются.

N:L;
{:F;0{:R;2md@2md@+F~!2I#*R+}64fI\;\;}:B{"2-"B}:A{'!B}:O{0SB}:N{'(B}:X];
{;Y32#__mr*\mr+}2e2%2/{~:U;:V;"A&O|X^"2/{[{US@SV" = "UV5$~L}/9$2$={];}{]oLo}?}/"N~"[{U" = "U3$~Y64#(&L}/6$2$={];}{]oLo}?}/
Runer112
источник
0

JavaScript 294 267

Был в состоянии побрить еще несколько байтов с предложениями @ AlexA. И @ kennytm.

Функции:

B=(n,m,t)=>{for(var p=4294967296,y=0;p>=1;p/=2)y+=t=='x'&&(n>=p||m>=p)&& !(n>=p&&m>=p)?p:0,y+=t=='a'&&n>=p&&m>=p?p:0,y+=t=='o'&&(n>=p||m>=p)?p:0,n-=n>=p?p:0,m-=m>=p?p:0
return y}
N=(n)=>{return 4294967295-n}
A=(n,m)=>B(n,m,'a')
O=(n,m)=>B(n,m,'o')
X=(n,m)=>B(n,m,'x')

пример:

var n = 300;
var m = 256;
console.log(X(n,m) + ", " + (n ^ m));
console.log(O(n,m) + ", " + (n | m));
console.log(A(n,m) + ", " + (n & m));
console.log(N(n) + ", " + (~n>>>0));
console.log(N(m) + ", " + (~m>>>0));

выход:

44, 44
300, 300
256, 256
4294966995, 4294966995
4294967039, 4294967039
wolfhammer
источник
2
Вам необходимо предоставить четыре общедоступных функции - по одной для AND, OR. НЕ и XOR. (У вас также могут быть общие / вспомогательные частные методы / функции, которые вызываются всеми четырьмя открытыми функциями). Кроме того, вы упускаете НЕ - возможно, самый простой из всех, что можно сделать
Digital Trauma
Спасибо @AlexA. Я добавил байты и поиграл еще немного.
Вольфхаммер
Вы можете потерять место после forи заменить function B(n,m,t)на B=(n,m,t)=>. Аналогично для других функций.
Алекс А.
① Вы можете использовать 4*(1<<30)для 4294967296 и -1>>>0для 4294967295. vartruly здесь действительно необходимо? ③ вы можете написать (n,m)=>B(n,m,'a')вместо(n,m)=>{return B(n,m,'a')}
kennytm