Нерозумно бітові операції


16

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

Виклик

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

Обмеження

Ви можете використовувати лише ті операції, які підтримує dc. Це:

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

Структури управління в dcмоєму бути незграбно побудовані, використовуючи (рекурсивні) макроси та (не) операції рівності. Ви можете використовувати будь-які вбудовані структури управління вашою мовою.

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

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

Крім того, ви не повинні використовувати вбудовані оператори чи функції базових перетворень рядків.


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


Чи можемо ми реалізувати одну функцію, яка приймає бажану операцію як параметр? Крім того, чи можемо ми ділити ціле число на 2 як резервне встановлення для зсуву бітів?
xnor

@xnor Ви повинні надати 4 загальнодоступні функції, які реалізують кожен із чотирьох операторів. Також у вас можуть бути загальні / помічні приватні методи / функції, які викликаються усіма чотирма загальнодоступними функціями, але всі вони повинні бути включені до оцінки гольфу.
Цифрова травма

7
@xnor Вам і вам потрібно також реалізувати оператора xnor ;-)
Digital Trauma

Чи можу я скласти список із чотирьох анонімних функцій?
xnor

@MariaTidalTug У чому полягає ефективна різниця між поверненням списку чотирьох функцій та ручним вибором та застосуванням однієї (як запропонував xnor), а не однією функцією, яка приймає параметр вибору та виконує сам вибір (як відповів вовкхамер)? Вони, схоже, аналогічно підривають сенс чотирьох названих функцій, оскільки вони завантажують розмір коду на код користувача. Я б навіть заперечував, що перший підриває його більше, оскільки код користувача, мабуть, складніший у тому випадку, ніж у другому.
Runer112

Відповіді:


4

С, 134

Препроцесором С досить весело зловживати. В основному цей макрос визначає 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));
        }
    }

1
ой. забув про це. виправили це зараз.
псевдонім117

4

витрачено 76 байт

Айд також не має побітових операцій - зазвичай це дратує, але зараз ласкаво просимо, тому що нам дійсно потрібно їх здійснити.

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

Перетворення на двійкові та з них:

@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 байт (з новими рядками та крапками з комою). Тестовий код буде просто (НЕ, АБО, І, 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

Я шукав причину навчитися нім, тому ось ми підемо.

Для кодового гольфу я використовував змінні параметри та неявну віддачу. Змінні параметри відповідно до документації є менш ефективними. Особисто я вважаю, що неявні повернення важче читати, і, ймовірно, використовую їх лише у тривіальних процедурах.

Що стосується алгоритмів, то вони досить прості. Для всіх операцій, крім НЕ, ми порівнюємо кожен біт і вручну порівнюємо їх із нашою очікуваною таблицею правдивості. Встановіть кожен біт за потребою в нашій вихідній змінній. У Nim результат - це неявне повернене значення.

Я не був впевнений, чи дозволено нам використовувати вбудовані АБО та І для встановлення двох булевих умов, тому процедура 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 .


@MariaTidalTug дякую за уточнення!
cory.todd

Я не можу цього відтворити. Ваш калькулятор у режимі базової 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.";

Тестовий набір

Цей тест коду виконує кожен з моїх, або, ні, і 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}?}/

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

2
Вам потрібно надати чотири загальнодоступні функції - по одній для І, АБО. НЕ і XOR. (У вас також можуть бути загальні / помічні приватні методи / функції, які викликаються усіма чотирма загальнодоступними функціями). Крім того, вам не вистачає НЕ - мабуть, найпростішого з усіх цих варіантів
Digital Trauma

Дякую @AlexA Я додав байтів і ще трохи пограв у нього.
вовчий молот

Ви можете втратити простір після forі замінити function B(n,m,t)на B=(n,m,t)=>. Так само і для інших функцій.
Олексій А.

① Ви можете використати 4*(1<<30)для 4294967296 і -1>>>0для 4294967295. ② чи varсправді потрібно тут? ③ ви могли написати (n,m)=>B(n,m,'a')замість(n,m)=>{return B(n,m,'a')}
kennytm
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.