/// <summary> /// Test Millera-Rabina czy liczba n jest pierwsza, przy danym a /// patrz: Cormen i "Alogrytmika praktyczna" (rozdzial 31.8) /// https://en.wikipedia.org/wiki/Miller–Rabin_primality_test /// /// Okresla czy liczba jest zlozona (true), podejrzenie ze pierwsza (false) /// </summary> /// <param name="a">podstawa</param> /// <param name="n">nieparzysta liczba do przetestowania</param> /// <returns>true - złożona, false - może być pierwsza</returns> public bool MillerRabinTest(long a, int n) { //dziala na zbiorze a [1, 2, .. n-1] if (a >= n) { return(false); } //n-1 = 2^t * u -> a^(n-1)=(a^n)^2^t, gdzie t>=1 i u nieparzyste long u = n - 1; long t = 0; while ((u & 1) == 0) { u /= 2; t++; } long x = NumbersTheory.ExpMod(a, u, n); long y = 0; for (; t > 0; t--) { y = (x * x) % n; //y = NumbersTheory.ExpMod(x, 2, n); if ((y == 1) && (x != 1) && (x != n - 1)) //nietrywialny dzielnik - liczba jest zlozona { return(true); } x = y; } //liczba jest zlozona jezeli y!=1 return(y != 1); }
public void TestLCM() { NumbersTheory.LCM(0, 56).ShouldBe(0); NumbersTheory.LCM(1, 56).ShouldBe(56); NumbersTheory.LCM(42, 56).ShouldBe(168); NumbersTheory.LCM(192, 348).ShouldBe(5568); }
public void TestGCDBinary() { NumbersTheory.GCDBinary(0, 0).ShouldBe(0); NumbersTheory.GCDBinary(10, 0).ShouldBe(10); NumbersTheory.GCDBinary(0, 10).ShouldBe(10); NumbersTheory.GCDBinary(1, 10).ShouldBe(1); NumbersTheory.GCDBinary(1, 100000000000).ShouldBe(1); NumbersTheory.GCDBinary(100000000000, 1).ShouldBe(1); NumbersTheory.GCDBinary(48, 180).ShouldBe(12); NumbersTheory.GCDBinary(180, 48).ShouldBe(12); }
public void TestGCDExt() { long l, k; long d; d = NumbersTheory.GCDExt(10, 15, out l, out k); d.ShouldBe(5); l.ShouldBe(-1); k.ShouldBe(1); d = NumbersTheory.GCDExt(123, 291, out l, out k); d.ShouldBe(3); l.ShouldBe(-26); k.ShouldBe(11); }
public void TestExpMod() { NumbersTheory.ExpMod(2, 0, 10).ShouldBe(1); NumbersTheory.ExpMod(1, 10, 10).ShouldBe(1); NumbersTheory.ExpMod(2, 100, 10).ShouldBe(6); NumbersTheory.ExpMod(3, 17, 123).ShouldBe(3); NumbersTheory.ExpMod(123456789, 2, 321).ShouldBe(90); NumbersTheory.ExpMod(1 << 32, (1 << 32) - 1, 999).ShouldBe(1); NumbersTheory.ExpMod(2, 32, 10).ShouldBe(6); NumbersTheory.ExpMod(2, 32, 2).ShouldBe(0); //NumbersTheory.ExpMod(2, 771604937422839, 1543209874845679).ShouldBe(1); }
/// <summary> /// sx, sy - rozmiar stolu (sx zawsze parzyste) /// px, py - polozenie kuli /// wx, wy - wektor ruchu/uderzenia /// </summary> /// <param name="sx"></param> /// <param name="sy"></param> /// <param name="px"></param> /// <param name="py"></param> /// <param name="wx"></param> /// <param name="wy"></param> /// <returns></returns> public Pocket CheckPocket(int sx, int sy, int px, int py, int wx, int wy) { //od razu w luzie if (IsMeshPoint(sx, sy, px, py)) { return(SpecifyPocket(sx, sy, px, py)); } //bez ruchu if ((wx == 0) && (wy == 0)) { return(Pocket.NIE); } //przypadki poziome if (wy == 0) { return(GetHorizontalPocket(sx, sy, px, py, wx)); } //przypadki pionowe if (wx == 0) { return(GetVerticalPocket(sx, px, wy)); } //i pozostale, liczone dla rucho w prawo do gory, inne warianty trzeba przeksztalcic //jezeli ruch w lewo to odbijamy stol wzgledem srodka bool tablefilppedvertical = (wx < 0); bool tableflippedhorizontal = (wy < 0); if (tablefilppedvertical) { FlipVertical(sx, ref px, ref wx); } if (tableflippedhorizontal) { FlipHorizontal(sy, ref py, ref wy); } //przeskalowanie wektora do najmniejszego mozliwego int wgcd = (int)NumbersTheory.GCDBinary(wx, wy); wx /= wgcd; wy /= wgcd; long a, b, c; a = (sx / 2) * wy; b = wx * py - wy * px; c = sy * wx; long n, m, p, q; n = a / c; m = NumbersTheory.Mod(a, c); p = b / c; q = NumbersTheory.Mod(b, c); //analizowane 4 przypadki A/C i B/C bool found = true; long coefa = 0; if ((m == 0) && (q == 0)) { //t > 0 -> a > px/w coefa = px / (sx / 2) + 1; } else if ((m == 0) && (q != 0)) { found = false; } else if ((m != 0) && (q == 0)) { coefa = c / NumbersTheory.GCDBinary(m, c); } else if ((m != 0) && (q != 0)) { long l, k; long d = NumbersTheory.GCDExt(m, c, out l, out k); if (-q % d == 0) { long x0 = NumbersTheory.Mod(l * (-q / d), c); coefa = x0; for (long i = 1; i < d; i++) //zgodnie z alg z Cormena powinno byc od 0, ale element 0 jest obliczony wczesniej { long xx = NumbersTheory.Mod(x0 + i * (c / d), c); if (xx < coefa) { coefa = xx; } } } else { found = false; } } //ustalenie punktu kratowego i luzy Pocket res = Pocket.NIE; if (found) { long t = (coefa * (sx / 2) - px) / wx; long rx = px + t * wx; long ry = py + t * wy; if (IsMeshPoint(sx, sy, rx, ry)) { res = SpecifyPocket(sx, sy, rx, ry); } } //korekta wyniku jezeli stol byl odbijany if (tablefilppedvertical) //ruch byl w lewo - stol byl odbity pionowo -> zamieniamy luzy lewe z prawymi { res = BackflipVertical(res); } if (tableflippedhorizontal) //ruch byl w dol - stol odbity poziomo -> zmieniamy luzy gorne i dolne { res = BackflipHorizontal(res); } return(res); }