Nim-Multiplikation

17

Hintergrund

Wenn Sie viel Code-Golf spielen, sind Sie sich wahrscheinlich der bitweisen XOR- Operation bewusst . Bei zwei Ganzzahlen gibt es eine weitere Ganzzahl mit 1s in den Bits, in denen sich die beiden Eingänge unterscheiden. Also zum Beispiel 1010 XOR 0011 = 1001.

Es erweist sich als sehr nützlich in der Spieltheorie, wo es besser als "Nimsumme" bekannt ist. Wenn Sie die Summe von zwei Spielen haben (dh, Sie bewegen sich in jeweils einem Spiel), ist der Wert der Position die Nimsumme der Werte der Positionen in jedem einzelnen Spiel.

Aber wir können noch einen Schritt weiter gehen. Mit der Addition von nim und einer geeigneten Definition der Multiplikation von nim können wir ein Feld aus den nichtnegativen ganzen Zahlen bilden. Die Herausforderung besteht also darin, nim Multiplikation zu spielen.

Definition

Die Nim-Multiplikation folgt den folgenden Regeln:
Das Nim-Produkt einer Fermat 2-Potenz n = (2 ^ (2 ^ k)) mit einer beliebigen kleineren Zahl ist das gewöhnliche Produkt.
Das Nullprodukt einer Fermat 2-Potenz n mit sich selbst ist 3n / 2.
Die Nim-Multiplikation verteilt sich auf die Nim-Addition.
Die Nim-Multiplikation ist kommutativ und assoziativ (ebenso wie die Nim-Addition).
Die multiplikative Identität ist 1 (und die additive Identität ist 0).

Jede nichtnegative Ganzzahl kann als NIM-Summe der unterschiedlichen Zweierpotenzen und jede Zweierpotenz als Produkt unterschiedlicher Fermat-Zahlen geschrieben werden. Dies ist also ausreichend, um die NIM-Multiplikation für alle nichtnegativen Ganzzahlen zu definieren.

Beispiel

Das war alles ziemlich abstrakt, also lasst uns ein Beispiel durcharbeiten. Ich werde +zur Bezeichnung der Nim-Addition (XOR) und *zur Nim-Multiplikation verwenden.

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

Zusätzliche Testfälle

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

Herausforderung

Schreiben Sie ein Programm oder eine Funktion, die mit zwei nichtnegativen ganzen Zahlen in beliebiger Form ihr NIM-Produkt berechnet.

Dies ist , also gewinnt die kürzeste Einreichung.


quelle
1
Falls es den Lesern nicht klar ist, unterscheidet sich dies von der XOR-Multiplikation (Carryless Multiplication) und ist daher kein Duplikat dieser Herausforderung.
xnor
1
Nim-Multiplikationstabellen in OEIS: A051775 , A051776 , A051910 , A051911 .
Arnauld
Beachten Sie auch, dass es keine intuitive Möglichkeit gibt, die Nimber-Multiplikation zu verstehen (laut diesem Beitrag).
user202729
Fermat-Nummern haben die Form 2 ^ (2 ^ k) +1, was Sie also eine Fermat-Nummer nennen, ist tatsächlich eins weniger.
Kelly Lowder
@ KellyLowder Ja, es ist wirklich ein Fermat 2-Power.

Antworten:

8

Nim , 120 Bytes

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

Probieren Sie es online!

OK, das mag verrückt sein, aber jemand musste Nim-Multiplikation in Nim machen ...

Dies ist ein Standardalgorithmus von Wikipedia. Das Problem ist, dass ich die Sprache nicht kenne und die Grundlagen schnell lernen musste. Insbesondere war ich überrasche , dass -=und minnicht für Sätze funktionieren, und der beste Weg , ich war zum Extrahieren des Minimums finden verwalten den Iterator zu verwenden und den ersten Wert zurück. Hoffentlich helfen mir Nim-Experten dabei, dies zu verbessern.

Kirill L.
quelle
2
Ich fragte mich, wann jemand das versuchen würde.
4

Gelee , 16 Bytes

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

Verwendet die rekursive Formel xy = mex ({ay ⊕ xb ⊕ ab: a <x, b <y}) für die Zahlenmultiplikation .

Probieren Sie es online!

Wie es funktioniert

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.
Dennis
quelle
4

CGSuite ,52 39 22 Bytes

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

Wusste nicht, dass es diese eingebauten und anonymen "Prozeduren" hat.

Originalversion, 36 Bytes:

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

Oder 25 Bytes, wenn die Eingabe / Ausgabe Zahlen sein könnte:

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

Nun, ich habe gehofft *a**b/ a*bzu arbeiten, aber das tut es nicht.

jimmy23013
quelle
Auf jeden Fall das richtige Werkzeug für den Job.
3

Pyth , 21 Bytes

Mf-TsmmxxgkdgkHgGdGH0

Demonstration

Verwendet das Minimum ausgeschlossen Element Formulierung von nim Multiplikation, als gegeben hier .

Zwei verschachtelte Maps werden verwendet, um alle kleineren Werte zu durchlaufen ( mm ... GH). Anschließend werden die Ergebnisse abgeflacht ( s). Der clevere Teil kommt mit f-T ... 0, bei dem wir ganze Zahlen von 0 nach oben durchlaufen, um den ersten Teil zu finden, der nicht in der oben genannten Menge enthalten ist. Auf diese Weise müssen wir keine obere Iterationsgrenze berechnen und ein paar Bytes einsparen.

Am Ende gberechnet die Funktion das NIM-Produkt.

isaacg
quelle
3

JavaScript (ES6), 142 128 Bytes

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>

Der erste Schritt besteht darin, beide xund yin ein XOR von Potenzen aufzuteilen 2, ihre paarweisen NIM-Produkte zu nehmen und dann die Ergebnisse zu XOR (da sich das NIM-Produkt über XOR verteilt). Sobald wir auf den Fall rekursiv haben xund ybeide Potenzen von 2, stellen wir fest, dass Fermat Kräfte mehrfach miteinander unter Verwendung von gewöhnlichen Arithmetik, so können wir daher faktorisieren xund yin Fermat Kräfte. Wenn Sie eine Fermat-Kraft haben xund ydiese nicht teilen, können Sie den Vorgang umkehren und einfach zurückkehren x * y. Wenn sie jedoch eine Fermat-Potenz teilen, teilen wir beide xund ydurch diese Potenz berechnen wir das Nim-Produkt und nehmen dann das Nim-Produkt mit dem Nim-Quadrat dieser Fermat-Potenz. Ungolfed:

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
}
Neil
quelle
1

Wolfram Language (Mathematica) , 81 Byte

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

Probieren Sie es online!

Mit der Formel:

αβ=mex({αβ+αβ+αβ:α<α,β<β}).

Alephalpha
quelle