ニム乗算


17

バックグラウンド

多くのコードゴルフを行う場合は、ビット単位のXOR操作を知っている可能性があります。2つの整数が与えられると1、2つの入力が異なるビットにsを持つ別の整数が与えられます。したがって、たとえば、1010 XOR 0011 = 1001

それはゲーム理論で非常に有用であることが判明し、「nim sum」として知られています。2つのゲームの合計がある場合(つまり、一度に1つのゲームで移動している場合)、位置の値は、個々のゲームの位置の値のnim合計です。

しかし、これをさらに一歩進めることができます。nimの追加とnimの乗算の適切な定義により、非負の整数からフィールドを形成できます。したがって、課題はゴルフニムの増殖です。

定義

Nim乗算は次の規則に従います
。Fermat 2乗n =(2 ^(2 ^ k))と任意の小さい数のnim積は通常の積です。
Fermat 2乗nとそれ自体のnim積は3n / 2です。
Nim乗算は、nim加算を介して分散します。
Nim乗算は可換および結合的です(nim加算と同様)。
乗法恒等式は1です(および加法恒等式は0です)。

非負の整数は、2の異なるべき乗のnimの合計として記述でき、2のべき乗は、異なるフェルマー数の積として記述できます。したがって、これは、すべての非負の整数の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

チャレンジ

任意の便利な形式の2つの非負整数が与えられた場合、nim積を計算するプログラムまたは関数を作成します。

これはなので、最短の提出が勝ちです。


1
読者に明らかでない場合、これはXOR(キャリーレス)乗算とは異なるため、そのチャレンジの複製ではありません。
xnor

1
ニムOEISでの乗算テーブル:A051775A051776A051910A051911
アーナウルド

また、(その投稿によると)木材の掛け算を理解する直感的な方法はないこと注意してください。
user202729

フェルマー数の形式は2 ^(2 ^ k)+1なので、フェルマー数と呼んでいるものは実際には1つ少なくなります。
ケリーロウダー

@KellyLowderはい、それは本当にFermat 2-powerです。

回答:


8

Nim、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

オンラインでお試しください!

OK、これはクレイジーかもしれませんが、誰かがNimでNim乗算をしなければなりませんでした...

これはウィキペディアの標準アルゴリズムです。問題は、言語がわからないため、その場で基本を学ばなければならなかったことです。具体的には、私がいることに驚いた-=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

CGSuite52 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乗算の最小除外要素定式化を使用します

2つのネストされたマップを使用してすべての小さい値を反復処理し(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>

最初のステップは、両方xyXの累乗のXOR に分割し、2それらのペアワイムnim製品を取得し、結果をXORします(nim製品はXORを介して配布されるため)。我々は、の場合に再帰した後xy2の両方のパワー我々は、したがってfactoriseできるように、我々は、互いに乗算フェルマーがパワー通常演算を使用していることに注意xし、yフェルマー電力に変換します。場合xyフェルマーの電源を共有していない私たちは、プロセスを逆にして、単純に返すことができますx * y。ただし、Fermatパワーを共有している場合は、両方xyそのパワーで除算し、nim製品を計算してから、そのFermatパワーのnim squareを使用してnim製品を取得します。ゴルフをしていない:

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
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.