Нім множення


17

Фон

Якщо ви багато займаєтеся гольфним кодом, ви, ймовірно, знаєте про побітну операцію XOR . Враховуючи два цілих числа, воно дає ще одне ціле число з 1s у бітах, де два входи відрізняються. Так, наприклад, 1010 XOR 0011 = 1001.

Це виявляється дуже корисним в теорії ігор, де вона більш відома як "nim sum". Якщо у вас є сума двох ігор (тобто ви робите рухи в одній грі за один раз), значення позиції - це повна сума значень позицій у кожній грі.

Але ми можемо зробити це на крок далі. За допомогою додавання nim та відповідного визначення множення nim ми можемо сформувати поле з невід’ємних цілих чисел. Тож завданням є розмноження нім для гольфу.

Визначення

Множення Нім підкоряється таким правилам:
Найменший добуток потужності Ферма 2-ї потужністю n = (2 ^ (2 ^ k)) з будь-яким меншим числом є звичайним добутком.
Нім добуток потужності n Fermat 2 потужністю 3n / 2.
Множення Nim розподіляється на додавання nim.
Множення Nim є комутативним та асоціативним (як і додавання nim).
Мультипликативна ідентичність дорівнює 1 (а ідентична добавка - 0).

Будь-яке невід'ємне ціле число може бути записане як нім сума сукупності різних потужностей двох, а будь-яка сила двох може бути записана як добуток різних чисел Ферма, тому цього достатньо, щоб визначити nim множення для всіх негативних чисел.

Приклад

Це все було досить абстрактно, тому давайте попрацюємо на прикладі. Я буду використовувати +для позначення додавання nim (XOR) та *для множення nim.

6 * 13
= (4 + 2) * (8 + 4 + 1)
= (4 + 2) * ((4 * 2) + 4 + 1)
= (4 * 4 * 2) + (4 * 2 * 2) + (4 * 4) + (4 * 2) + (4 * 1) + (2 * 1)
= (6 * 2) + (4 * 3) + 6 + 8 + 4 + 2
= ((4 + 2) * 2) + 12 + 6 + 8 + 4 + 2
= (4 * 2) + (2 * 2) + 12 + 6 + 8 + 4 + 2
= 8 + 3 + 12 + 6 + 8 + 4 + 2
= 15

Додаткові випробувальні випадки

4, 4 -> 6
4, 3 -> 12
4, 7 -> 10
2, 4 -> 8
2, 3 -> 1
1, 42 -> 42

Виклик

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

Це , тому виграє найкоротше подання.


1
Якщо читачам це не зрозуміло, це відмінність від множення XOR (несучої), і тому не дублікат цього виклику.
xnor

1
Таблиці множення Nim в OEIS: A051775 , A051776 , A051910 , A051911 .
Арнольд

Також зауважте, що не існує інтуїтивного способу зрозуміти множення німбер (відповідно до цього допису).
користувач202729

Номери Ферма мають форму 2 ^ (2 ^ k) +1, тому те, що ви називаєте числом Ферма, насправді на менше.
Келлі Лоудер

@KellyLowder Так, це дійсно Fermat 2-сильний.

Відповіді:


8

Нім , 120 байт

proc f(a,b:int):int=
 var s={0..a*b}
 for i in 0..<a*b:s=s-{f(i%%a,i/%a)xor f(a,i/%a)xor f(i%%a,b)}
 for i in s:return i

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

Гаразд, це може бути божевільним, але хтось повинен був зробити множення Німа в Німі ...

Це стандартний алгоритм з Вікіпедії. Проблема в тому, що я не знаю мови, тому доводилося вивчати основи на льоту. Зокрема, я був здивований , що -=і minне працює для множин, і кращий спосіб мені вдалося знайти для вилучення мінімум повинен був використовувати итератор і повертає перше значення. Сподіваюся, фахівці компанії Nim допоможуть мені покращити це.


2
Мені було цікаво, коли хтось спробує це.


4

Желе , 16 байт

p’ß/;ß"^/ʋ€ṭ‘ḟ$Ṃ

Використовується рекурсивна формула xy = mex ({ay ⊕ xb ⊕ ab: a <x, b <y}) для множення німбер .

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

Як це працює

p’ß/;ß"^/ʋ€ṭ‘ḟ$Ṃ  Main link. Left argument: x. Right argument: y.

p                 Cartesian product; yield the array of all pairs [a, b] such that
                  0 < a ≤ x and 0 < b ≤ y.
 ’                Decrement, changing the conditions to 0 ≤ a < x and 0 ≤ b < y.
          ṭ       Tack; yield [y, x].
        ʋ€        Combine the four links to the left into a dyadic chain. Call it
                  with right argument [y, x] and each of the [a, b] as left one.
  ß/                  Reduce [a, b] by the main link, computing the product ab.
     ß"               Zip [a, b] with [y, x] using the main link, computing the
                      array of products [ay, xb].
    ;                 Concatenate, yielding [ab, ay, xb].
       ^/             Reduce by bitwise XOR, yielding ab ⊕ ay ⊕ xb.
                  All that's left is to compute the minimum excluded (mex) non-
                  negative integer.
             $    Combine the two links to the left into a monadic chain.
           ‘          Increment the XOR sums.
            ḟ         Filterfalse; remove all incremented sums that appear in the
                      original sums.
              Ṃ  Take the minimum if the resulting array is non-empty or yield 0.
                 If x = 0 or y = 0, the array of sums is empty and Ṃ yields 0.
                 If x > 0 and y > 0, since 0 is among the sums, this finds the
                 smallest non-sum n+1 such that n ≥ 0 is a sum.
                 In either case, Ṃ yields xy.

4

CGSuite ,52 39 22 байти

(a,b)->a.NimProduct(b)

Не усвідомлював, що в цьому є вбудований і анонімний "порядок".

Оригінальна версія, 36 байт:

(a,b)->*a.ConwayProduct(*b).NimValue

Або 25 байт, якщо вхід / вихід може бути нумерами:

(a,b)->a.ConwayProduct(b)

Ну, я сподівався *a**b/ a*bпопрацював, але це не так.


Однозначно правильний інструмент для роботи.

3

Pyth , 21 байт

Mf-TsmmxxgkdgkHgGdGH0

Демонстрація

Використовується мінімальна формула виключеного елемента множення nim, як зазначено тут .

Дві вкладені карти використовуються для ітерації всіх менших значень ( mm ... GH), потім результати вирівнюються ( s). Розумна частина йде разом f-T ... 0, де ми повторюємо цілі числа вгору від 0, щоб знайти перше, що не міститься у згаданому вище наборі. Роблячи це таким чином, нам не потрібно обчислювати верхню межу ітерації, економлячи кілька байт.

Зрештою, функція gобчислює nim добуток.


3

JavaScript (ES6), 142 128 байт

f=(x,y,z=Math.log2,v=x&-x,t=z(x),u=z(y),s=t&u,r=s&-s)=>x<2|y<2?x*y:x>v?f(v,y)^f(x^v,y):y&y-1?f(y,x):r?f(f(x>>r,y>>r),3<<r-1):x*y
<div oninput=o.textContent=f(x.value,y.value)><input id=x><input id=y><pre id=o>

Перший крок - це розділити обидва xта yна XOR повноважень 2, взяти їх парні nim продукти, а потім XOR результати (оскільки nim продукт поширюється на XOR). Після того, як ми повернемось до випадку xі yобох потужностей 2, ми зауважимо, що сили Ферма множиться між собою, використовуючи звичайну арифметику, тому ми можемо розбити фактор xі yперетворити на сили Ферма. Якщо xі yне поділяємо потужність Fermat, ми можемо повернути процес і просто повернутися x * y. Однак якщо вони поділяють потужність Ферма, то ми ділимо обидві xі yна цю потужність, обчислюємо nim добуток, а потім беремо nim добуток з nim квадрата цієї потужності Fermat. Безумовно:

function nimprod(x, y) {
    if (x < 2 || y < 2) return x * y;
    var v = x & -x;
    if (x > v) return nimprod(v, y) ^ nimprod(x ^ v, y); // nimprod distributes over ^
    if (y & (y - 1)) return nimprod(y, x); // x is a power of 2 but y is not
    var t = Math.log2(x);
    var u = Math.log2(y);
    var s = t & u;
    if (!s) return x * y; // x and y do not share a Fermat power
    var r = s & -s;
    return nimprod(nimprod(x >> r, y >> r), 3 << r - 1); // square the Fermat power
}

1

Мова Вольфрама (Mathematica) , 81 байт

x_±y_:=Min@Complement[Range[0,x*y],##&@@Array[BitXor[x±#2,#±y,±##]&,{x,y},0]]

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

Використовуючи формулу:

αβ=мекс({α'β+αβ'+α'β':α'<α,β'<β}).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.