static public List <Zyklus> TrefferBestimmen(BigInteger n, int[] zahlensysteme) { List <Zyklus> result = new List <Zyklus>(); List <MddPaarImZahlensystem> mdPaare = mdPaareBestimmen(n, zahlensysteme); // Triviale Lösung wird an anderer Stelle geprüft var startwert = Helper.Wurzel(n); int maxSequenz = zahlensysteme.Max() * zahlensysteme.Max(); BigInteger[] arbeitsSequenzM_ = new BigInteger[maxSequenz + 1]; BigInteger[] arbeitsSequenzDD = new BigInteger[maxSequenz + 1]; // da der Startwert sonst negativ ist, wenn nicht die Wurzel die Lösung ist BigInteger m = BigInteger.Add(startwert.Item1, 1); BigInteger wurzelDelta = BigInteger.Add(BigInteger.Multiply(2, m), 1); // Sequenz einmalig berechnen arbeitsSequenzM_[0] = m; arbeitsSequenzDD[0] = BigInteger.Subtract(BigInteger.Pow(m, 2), n); for (int i = 1; i <= maxSequenz; i++) { arbeitsSequenzM_[i] = BigInteger.Add(arbeitsSequenzM_[i - 1], 1); arbeitsSequenzDD[i] = BigInteger.Add(arbeitsSequenzDD[i - 1], wurzelDelta); wurzelDelta = BigInteger.Add(wurzelDelta, 2); } // Die Zahlen ins entsprechende Zahlensystem umwandeln und "Treffer" merken // Es werden nur die Abstände zwischen zwei "Treffern" vermerkt //int potenz; BigInteger tmpM_; BigInteger tmpDD; foreach (MddPaarImZahlensystem paar in mdPaare) { List <long> sequenz = new List <long>(); //potenz = paar.Zahlensystem * paar.Zahlensystem; int zahlensystem = paar.Zahlensystem; for (int j = 0; j < zahlensystem; j++) { BigInteger.DivRem(arbeitsSequenzM_[j], zahlensystem, out tmpM_); BigInteger.DivRem(arbeitsSequenzDD[j], zahlensystem, out tmpDD); if (paar.MddPaar.Exists(x => ((x.Item1 == tmpM_) && (x.Item2 == tmpDD)))) { sequenz.Add(j); } } Zyklus zyklus = new Zyklus(zahlensystem, sequenz.ToArray <long>()); Zyklus.ZyklusVerkuerzen(ref zyklus); result.Add(zyklus); } return(result); }
static public void ZyklusVerkuerzen(ref Zyklus zyklus) { // Zyklus mit keinem oder einem Element werden auf sich selbst abgebildet if (zyklus.NumberOfElements < 2) { return; } // Prüfe, ob sich wiederholende Teilsequenzen finden lassen int alteAnzahlDerElemente = zyklus.NumberOfElements; // Erste Element int neueAnzahlDerElemente = 1; long differenz = zyklus.Elemente[1] - zyklus.Elemente[0]; // Sucht ab dem zweiten Element nach einem Element, welches den gleichen Wert wie das Erste hat. // -> In dem Fall wird geschaut, ob alle folgenden Elemente gilt: E[i] == E[i+offset] for (int i = 2; i < alteAnzahlDerElemente; i++) { if (zyklus.Elemente[i] != (zyklus.Elemente[i - neueAnzahlDerElemente] + differenz)) { neueAnzahlDerElemente = i; differenz = zyklus.Elemente[i] - zyklus.Elemente[0]; } } // Letztes Element if ((zyklus.Elemente[0] + zyklus.ZyklusSumme) != (zyklus.Elemente[alteAnzahlDerElemente - neueAnzahlDerElemente] + differenz)) { neueAnzahlDerElemente = alteAnzahlDerElemente; } // Prüfe, ob die Teilsequenzen als n-fache einen echten Zyklus bilden if (neueAnzahlDerElemente == alteAnzahlDerElemente) { return; } // Zyklus ist keine "sinnvoll teilbare" Teilmenge // Bsp: [7 5 8 8 7 5] if (alteAnzahlDerElemente % neueAnzahlDerElemente != 0) { return; } Console.WriteLine($"Zyklus komprimiert: {zyklus.ZyklusSumme} : {alteAnzahlDerElemente} -> {neueAnzahlDerElemente}"); Console.WriteLine($"[{string.Join(",", zyklus.Elemente)}]"); zyklus.Truncate(neueAnzahlDerElemente); zyklus.ZyklusSumme = (zyklus.ZyklusSumme * neueAnzahlDerElemente) / alteAnzahlDerElemente; return; }
static public Zyklus EndgueltigenZyklusBestimmen(BigInteger n, int[] zahlensysteme) { List <Zyklus> zyklen = TrefferBestimmen(n, zahlensysteme); Zyklus endgueltigerZyklus = zyklen[0]; for (int i = 1; i < zyklen.Count; i++) { endgueltigerZyklus = Zyklus.VerschmelzeZyklen(zyklen[i], endgueltigerZyklus); } Console.WriteLine($"Kombiniert: {endgueltigerZyklus.NumberOfElements,3:0} / {endgueltigerZyklus.ZyklusSumme,3:0} = {(endgueltigerZyklus.NumberOfElements / (double)endgueltigerZyklus.ZyklusSumme)}"); return(endgueltigerZyklus); }
static public (BigInteger A, BigInteger B) Run(BigInteger n, int[] zahlensysteme) { var startwert = Helper.Wurzel(n); if (startwert.Item2 == true) { Console.WriteLine(string.Format("Lösung ist die Wurzel {0}", startwert.Sqrt)); return(startwert.Item1, startwert.Item1); } Zyklus zyklus = EndgueltigenZyklusBestimmen(n, zahlensysteme); zyklus.Sort(); (BigInteger, bool)ergebnisDerWurzel; BigInteger offset = BigInteger.Add(startwert.Item1, 1); while (true) { for (int i = 0; i < zyklus.NumberOfElements; i++) { // Formel: ab = SQRT( (x*x) - n) | mit x := x+1 ergebnisDerWurzel = Helper.Wurzel(BigInteger.Subtract(BigInteger.Pow(BigInteger.Add(offset, zyklus.Elemente[i]), 2), n)); if (ergebnisDerWurzel.Item2 == true) { BigInteger a = BigInteger.Add(BigInteger.Add(offset, zyklus.Elemente[i]), ergebnisDerWurzel.Item1); BigInteger b = BigInteger.Subtract(BigInteger.Add(offset, zyklus.Elemente[i]), ergebnisDerWurzel.Item1); return(a, b); } } offset = BigInteger.Add(offset, zyklus.ZyklusSumme); } }
static public Zyklus VerschmelzeZyklen(Zyklus zyklusA, Zyklus zyklusB) { Zyklus A; Zyklus B; if (zyklusA.ZyklusSumme > zyklusB.ZyklusSumme) { A = zyklusA; B = zyklusB; } else { A = zyklusB; B = zyklusA; } long ergebnisZyklusSumme; if (A.ZyklusSumme % B.ZyklusSumme == 0) { ergebnisZyklusSumme = A.ZyklusSumme; } else { ergebnisZyklusSumme = A.ZyklusSumme * B.ZyklusSumme; } Tuple <long, long> offset = BestimmeOffsetZahlenZweierZyklen(A.ZyklusSumme, B.ZyklusSumme); Zyklus ergebnis = new Zyklus(ergebnisZyklusSumme, A.NumberOfElements * B.NumberOfElements); long tmp; long tmp2; for (int i = 0; i < A.NumberOfElements; i++) { for (int j = 0; j < B.NumberOfElements; j++) { tmp = B.Elemente[j] - A.Elemente[i]; if (tmp == 0) { ergebnis.Elemente.Add(A.Elemente[i]); } else { tmp2 = ((offset.Item2 * tmp) % A.ZyklusSumme) * B.ZyklusSumme + B.Elemente[j]; tmp2 = (tmp2 + ergebnisZyklusSumme) % ergebnisZyklusSumme; // Zyklus positiv halten if (tmp2 < 0) { int k = 0; k++; } ergebnis.Elemente.Add(tmp2); } } } return(ergebnis); }