Nim Multiplication

17

Contexte

Si vous jouez beaucoup au code, vous êtes probablement au courant de l' opération XOR au niveau du bit . Étant donné deux entiers, il donne un autre entier avec 1s dans les bits où les deux entrées diffèrent. Ainsi, par exemple 1010 XOR 0011 = 1001,.

Il s'avère très utile dans la théorie des jeux, où il est mieux connu sous le nom de «nim sum». Si vous avez la somme de deux jeux (c'est-à-dire que vous effectuez des mouvements dans un jeu à la fois), la valeur de la position est la somme nim des valeurs des positions dans chaque jeu individuel.

Mais nous pouvons aller plus loin. Avec l'addition nim et une définition appropriée de la multiplication nim , nous pouvons former un champ à partir des entiers non négatifs. Le défi consiste donc à multiplier les nim au golf.

Définition

La multiplication Nim obéit aux règles suivantes:
Le produit nim d'un Fermat 2-puissance n = (2 ^ (2 ^ k)) avec un nombre plus petit est le produit ordinaire.
Le produit nim d'un n de Fermat 2-power est lui-même 3n / 2.
La multiplication Nim distribue sur l'addition nim.
La multiplication Nim est commutative et associative (tout comme l'addition nim).
L'identité multiplicative est 1 (et l'identité additive est 0).

Tout entier non négatif peut être écrit comme la somme nim de puissances distinctes de deux, et toute puissance de deux peut être écrite comme le produit de nombres Fermat distincts, donc cela suffit pour définir la multiplication nim pour tous les entiers non négatifs.

Exemple

Tout cela était assez abstrait, alors travaillons à travers un exemple. Je vais utiliser +pour désigner l'addition nim (XOR) et *pour la multiplication 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

Cas de test supplémentaires

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

Défi

Écrivez un programme ou une fonction qui, étant donné deux entiers non négatifs sous n'importe quelle forme pratique, calcule leur produit nim.

C'est , donc la soumission la plus courte l'emporte.


la source
1
Dans le cas où ce n'est pas clair pour les lecteurs, cela est différent de la multiplication XOR (sans portage), et donc pas un double de ce défi.
xnor
1
Tables de multiplication Nim dans OEIS: A051775 , A051776 , A051910 , A051911 .
Arnauld
Notez également qu'il n'existe aucun moyen intuitif de comprendre la multiplication du nimber (selon ce post).
user202729
Les nombres Fermat sont de la forme 2 ^ (2 ^ k) +1, donc ce que vous appelez un numéro Fermat est en fait un de moins.
Kelly Lowder
@KellyLowder Oui, c'est vraiment un Fermat 2-power.

Réponses:

8

Nim , 120 octets

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

Essayez-le en ligne!

OK, cela peut être fou, mais quelqu'un a dû faire une multiplication Nim dans Nim ...

Il s'agit d'un algorithme standard de Wikipedia. Le problème est que je ne connais pas la langue, donc j'ai dû apprendre les bases à la volée. En particulier, cela m'a surpris -=et minn'a pas fonctionné pour les ensembles, et le meilleur moyen que j'ai réussi à trouver pour extraire le minimum était d'utiliser l'itérateur et de renvoyer la première valeur. Espérons que les experts Nim m'aideront à améliorer cela.

Kirill L.
la source
2
Je me demandais quand quelqu'un essaierait ça.
4

Gelée , 16 octets

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

Utilise la formule récursive xy = mex ({ay ⊕ xb ⊕ ab: a <x, b <y}) pour la multiplication du nombre .

Essayez-le en ligne!

Comment ça fonctionne

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
la source
4

CGSuite ,52 39 22 octets

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

Je ne savais pas qu'il avait cette "procédure" intégrée et anonyme.

Version originale, 36 octets:

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

Ou 25 octets si l'entrée / sortie peut être des nombres:

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

Eh bien, j'espérais *a**b/ a*btravailler, mais ça ne marche pas.

jimmy23013
la source
Certainement le bon outil pour le travail.
3

Pyth , 21 octets

Mf-TsmmxxgkdgkHgGdGH0

Manifestation

Utilise la formulation d'élément exclu minimum de multiplication nim, comme indiqué ici .

Deux cartes imbriquées sont utilisées pour itérer sur toutes les valeurs plus petites ( mm ... GH), puis les résultats sont aplatis ( s). La partie intelligente est livrée avec f-T ... 0, où nous parcourons les entiers vers le haut à partir de 0 pour trouver le premier non contenu dans l'ensemble mentionné ci-dessus. En procédant de cette façon, nous n'avons pas besoin de calculer une limite supérieure d'itération, économisant quelques octets.

Au final, la fonction gcalcule le produit nim.

isaacg
la source
3

JavaScript (ES6), 142 128 octets

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>

La première étape consiste à diviser les deux xet yen un XOR de pouvoirs de 2, prendre leurs produits nim par paire, puis XOR les résultats (car le produit nim se distribue sur XOR). Une fois que nous sommes revenus au cas de xet aux ydeux puissances de 2, nous notons que les puissances de Fermat se multiplient entre elles en utilisant l'arithmétique ordinaire, nous pouvons donc factoriser xet yen puissances de Fermat. Si xet yne partagent pas une puissance Fermat , nous pouvons inverser le processus et revenir simplement x * y. Cependant, s'ils partagent une puissance de Fermat, alors nous divisons les deux xet ypar cette puissance, calculons le produit nim, puis prenons le produit nim avec le carré nim de cette puissance de Fermat. Non golfé:

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
la source
1

Wolfram Language (Mathematica) , 81 octets

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

Essayez-le en ligne!

En utilisant la formule:

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

alephalpha
la source