Berechnen Sie eine Wahrscheinlichkeit genau und schnell

10

[Dies ist eine Partnerfrage, um eine Wahrscheinlichkeit genau zu berechnen ]

Bei dieser Aufgabe geht es darum, Code zu schreiben, um eine Wahrscheinlichkeit genau und schnell zu berechnen . Die Ausgabe sollte eine genaue Wahrscheinlichkeit sein, die als Bruch in ihrer am meisten reduzierten Form geschrieben wird. Das heißt, es sollte nie ausgegeben werden 4/8, sondern 1/2.

nBetrachten Sie für eine positive Ganzzahl eine gleichmäßig zufällige Zeichenfolge mit einer Länge von 1s und -1s nund nennen Sie sie A. Verketten Sie nun mit Aihrem ersten Wert. Das heißt, A[1] = A[n+1]wenn die Indizierung von 1. Ajetzt Länge hat n+1. Nun auch eine zweite zufällige Zeichenfolge der Länge betrachten , nderen erste nWerte -1, 0 oder 1 , mit einer Wahrscheinlichkeit von 1 / 4,1 / 2, 1/4 und jedes nennen es B.

Betrachten Sie nun das innere Produkt von A[1,...,n]und Bund das innere Produkt von A[2,...,n+1]und B.

Betrachten Sie zum Beispiel n=3. Mögliche Werte für Aund Bkönnten A = [-1,1,1,-1]und sein B=[0,1,-1]. In diesem Fall sind die beiden inneren Produkte 0und 2.

Ihr Code muss die Wahrscheinlichkeit ausgeben, dass beide inneren Produkte Null sind.

Wenn wir die von Martin Büttner erstellte Tabelle kopieren, erhalten wir die folgenden Beispielergebnisse.

n   P(n)
1   1/2
2   3/8
3   7/32
4   89/512
5   269/2048
6   903/8192
7   3035/32768
8   169801/2097152

Sprachen und Bibliotheken

Sie können jede frei verfügbare Sprache und Bibliothek verwenden, die Sie mögen. Ich muss in der Lage sein, Ihren Code auszuführen. Bitte geben Sie eine vollständige Erklärung an, wie Sie Ihren Code unter Linux ausführen / kompilieren können, wenn dies überhaupt möglich ist.

Die Aufgabe

Ihr Code muss mit beginnen n=1und die richtige Ausgabe für jedes zunehmende n in einer separaten Zeile angeben. Es sollte nach 10 Sekunden aufhören.

Die Punktzahl

Die Punktzahl ist einfach die höchste, die nerreicht wird, bevor Ihr Code nach 10 Sekunden auf meinem Computer stoppt. Wenn es ein Unentschieden gibt, ist der Gewinner derjenige, der am schnellsten die höchste Punktzahl erreicht.

Tabelle der Einträge

  • n = 64in Python . Version 1 von Mitch Schwartz
  • n = 106in Python . Version 11. Juni 2015 von Mitch Schwartz
  • n = 151in C ++ . Port of Mitch Schwartz 'Antwort von kirbyfan64sos
  • n = 165in Python . Version 11. Juni 2015 die "Schnitt" -Version von Mitch Schwartz mit N_MAX = 165.
  • n = 945in Python von Min_25 mit einer genauen Formel. Tolle!
  • n = 1228in Python von Mitch Schwartz unter Verwendung einer anderen exakten Formel (basierend auf der vorherigen Antwort von Min_25).
  • n = 2761in Python von Mitch Schwartz mit einer schnelleren Implementierung derselben exakten Formel.
  • n = 3250in Python mit Pypy von Mitch Schwartz mit der gleichen Implementierung. Diese Punktzahl muss pypy MitchSchwartz-faster.py |tailvermeiden, dass die Konsole über den Bildlauf blättert.
Gemeinschaft
quelle
Ich frage mich, ob eine numpy Lösung schneller als Boost C ++ laufen würde?
qwr
@qwr Ich denke, Numpy, Numba und Cython wären alle interessant, da sie in der Python-Familie bleiben.
2
Ich würde gerne mehr von diesen Problemen mit dem schnellsten Code sehen
qwr
@qwr es ist meine Lieblingsfrage ... Danke! Die Herausforderung besteht darin, einen zu finden, bei dem nicht nur genau derselbe Algorithmus in der niedrigsten Sprache codiert wird, die Sie finden können.
Schreiben Sie die Ergebnisse in die Konsole oder in eine Datei? Pypy zu verwenden und in eine Datei zu schreiben, scheint mir am schnellsten zu sein. Die Konsole verlangsamt den Prozess erheblich.
Gnibbler

Antworten:

24

Python

Eine geschlossene Formel von p(n)ist

Geben Sie hier die Bildbeschreibung ein

Eine exponentielle Erzeugungsfunktion von p(n)ist

Geben Sie hier die Bildbeschreibung ein

wo I_0(x)ist die modifizierte Bessel-Funktion der ersten Art.

Bearbeiten am 11.06.2015:
- Der Python-Code wurde aktualisiert.

Bearbeiten am 13.06.2015:
- Ein Beweis für die obige Formel wurde hinzugefügt.
- behoben die time_limit.
- einen PARI / GP-Code hinzugefügt.

Python

def solve():
  # straightforward implementation

  from time import time
  from itertools import count

  def binom(n, r):
    return facts[n] // (facts[r] * facts[n - r])

  def p(N):
    ans = 0
    for i in range(1 + N // 2):
      t = binom(2 * (N - 2 * i), N - 2 * i)
      t *= binom(N, 2 * i)
      t *= binom(4 * i, 2 * i)
      ans += t
    e = (ans & -ans).bit_length() - 1
    numer = ans >> e
    denom = 1 << (3 * N - 1 - e)
    return numer, denom

  facts = [1]
  time_limit = 10.0 + time()

  for i in count(1):
    facts.append(facts[-1] * (2 * i - 1))
    facts.append(facts[-1] * (2 * i))

    n, d = p(i)

    if time() > time_limit:
      break

    print("%d %d/%d" % (i, n, d))

solve()

PARI / GP

p(n) = polcoeff( (exp(x/2) + 1) * besseli(0, x/4) ^ 2, n) * n!;

Beweis:
Dieses Problem ähnelt einem zweidimensionalen (eingeschränkten) Random-Walk-Problem.

Wenn A[i] = A[i+1], können wir aus bewegen (x, y)zu (x+1, y+1)[1 Art und Weise], (x, y)[2 Wegen] oder (x-1, y-1)[1 Art und Weise].

Wenn A[i] != A[i+1], können wir aus bewegen (x, y)zu (x-1, y+1)[1 Art und Weise], (x, y)[2 Wegen] oder (x+1, y-1)[1 Art und Weise].

Lassen Sie a(n, m) = [x^m]((x+1)^n + (x-1)^n), b(n) = [x^n](1+x)^{2n}und c(n)kann die Anzahl der Möglichkeiten , von sich zu bewegen , (0, 0)um (0, 0)mit nSchritten.

Dann, c(n) = \sum_{i=0}^n a(n, i) * b(i) * b(n-i).

Da p(n) = c(n) / 8^nkönnen wir die obige Formel in geschlossener Form erhalten.

Min_25
quelle
1
Das ist ... na ja ... unglaublich! Wie um alles in der Welt haben Sie die genaue Formel berechnet?
1
Beeindruckend! Geschlossene Form ist immer ordentlich!
qwr
1
@Lembik: Ich habe einen (groben) Beweis hinzugefügt.
Min_25
1
@qwr: Danke. Das denke ich auch !
Min_25
1
@ mbomb007: Ja. Es handelt sich jedoch eher um eine Implementierungsaufgabe als um eine Computeraufgabe. Also würde ich es nicht in C ++ codieren.
Min_25
9

Python

Hinweis: Herzlichen Glückwunsch an Min_25 zur Suche nach einer geschlossenen Lösung!

Danke für das interessante Problem! Es kann mit DP gelöst werden, obwohl ich mich derzeit nicht sehr motiviert fühle, die Geschwindigkeit zu optimieren, um eine höhere Punktzahl zu erzielen. Es könnte schön zum Golfen sein.

Der Code erreichte N=39innerhalb von 10 Sekunden auf diesem alten Laptop mit Python 2.7.5.

from time import*
from fractions import*
from collections import*

X={(1,0,0,0):1,(-1,0,0,0):1}

T=time()
N=0

while 1:
    Y=defaultdict(lambda:0)
    n=d=0
    for a,b,s,t in X:
        c=X[(a,b,s,t)]
        for A in ( (1,-1) if N else [a] ):
            for B in 1,0,0,-1:
                n+=c*(s+A*B==0==t+A*b+a*B)
                d+=c
                Y[(a,B,s+A*B,t+A*b)]+=c
    if time()>T+10: break
    N+=1
    print N,Fraction(n,d)
    X=Y

Für Tupel (a,b,s,t): aist das erste Element von A, bist das letzte Element von B, sist das innere Produkt von A[:-1]und Bund tist das innere Produkt von A[1:-1]und B[:-1]unter Verwendung der Python-Slice-Notation. Mein Code speichert nicht die Arrays Aoder Büberall, so dass ich diese Briefe verwenden , um die nächsten Elemente beziehen hinzugefügt werden Aund Bsind. Diese Wahl der Variablennamen macht die Erklärung etwas umständlich, ermöglicht jedoch ein ansprechendes Aussehen A*b+a*Bim Code selbst. Beachten Sie, dass das hinzugefügte Element Adas vorletzte ist, da das letzte Element immer das gleiche ist wie das erste. Ich habe Martin Büttners Trick angewendet, 0zweimal dabei zu seinBKandidaten, um die richtige Wahrscheinlichkeitsverteilung zu erhalten. Das Wörterbuch X(die Namen Yfür N+1entsprechend den Wert des Tupels) hält die Zählung aller möglichen Arrays verfolgen. Die Variablen nund dstehen für Zähler und Nenner, weshalb ich die nder Problemstellung in umbenannt habe N.

Der wichtigste Teil der Logik ist , dass Sie aus aktualisieren können , Num N+1mit nur die Werte im Tupel. Die beiden in der Frage angegebenen inneren Produkte sind durch s+A*Bund gegeben t+A*b+a*B. Dies ist klar, wenn Sie die Definitionen ein wenig untersuchen. beachten Sie, dass , [A,a]und [b,B]die letzten beiden Elemente des Arrays Aund Bjeweils.

Beachten Sie, dass sund tklein und begrenzt Nsind. Für eine schnelle Implementierung in einer schnellen Sprache könnten wir Wörterbücher zugunsten von Arrays vermeiden.

Es kann möglich sein, die Symmetrie zu nutzen, wenn Werte berücksichtigt werden, die sich nur im Vorzeichen unterscheiden. Ich habe das nicht untersucht.

Bemerkung 1 : Die Größe des Wörterbuchs wächst quadratisch N, wobei Größe die Anzahl der Schlüssel-Wert-Paare bedeutet.

Bemerkung 2 : Wenn wir eine Obergrenze festlegen N, können wir Tupel beschneiden, für die N_MAX - N <= |s|und in ähnlicher Weise für t. Dies könnte durch Angabe eines absorbierenden Zustands oder implizit mit einer Variablen erfolgen, die die Anzahl der beschnittenen Zustände enthält (die bei jeder Iteration mit 8 multipliziert werden müssten).

Update : Diese Version ist schneller:

from time import*
from fractions import*
from collections import*

N_MAX=115

def main():
    T=time()

    N=1
    Y={(1,0,0,0):1,(1,1,1,0):1}
    n=1
    thresh=N_MAX

    while time() <= T+10:
        print('%d %s'%(N,Fraction(n,8**N/4)))

        N+=1
        X=Y
        Y=defaultdict(lambda:0)
        n=0

        if thresh<2:
            print('reached MAX_N with %.2f seconds remaining'%(T+10-time()))
            return

        for a,b,s,t in X:
            if not abs(s)<thresh>=abs(t):
                continue

            c=X[(a,b,s,t)]

            # 1,1

            if not s+1 and not t+b+a: n+=c
            Y[(a,1,s+1,t+b)]+=c

            # -1,1

            if not s-1 and not t-b+a: n+=c
            Y[(a,1,s-1,t-b)]+=c

            # 1,-1

            if not s-1 and not t+b-a: n+=c
            Y[(a,-1,s-1,t+b)]+=c

            # -1,-1

            if not s+1 and not t-b-a: n+=c
            Y[(a,-1,s+1,t-b)]+=c

            # 1,0

            c+=c

            if not s and not t+b: n+=c
            Y[(a,0,s,t+b)]+=c

            # -1,0

            if not s and not t-b: n+=c
            Y[(a,0,s,t-b)]+=c

        thresh-=1

main()

Optimierungen implementiert:

  • Alles in main()- lokaler Variablenzugriff ist schneller als global
  • Griff N=1explizit den Scheck zu vermeiden (1,-1) if N else [a](was die in dem Tupel das erste Element erzwingt konsistent ist, wenn die Elemente auf dem Hinzufügen Aausgehend von der leeren Liste)
  • Rollen Sie die inneren Schleifen ab, wodurch auch die Multiplikation entfällt
  • Verdoppeln Sie die Anzahl cfür das Hinzufügen von a 0zu, Banstatt diese Vorgänge zweimal auszuführen
  • Der Nenner ist immer 8^Nso, dass wir ihn nicht im Auge behalten müssen
  • jetzt unter Berücksichtigung der Symmetrie: Wir können das erste Element von Aas festlegen 1und den Nenner durch dividieren 2, da die gültigen Paare (A,B)mit A[1]=1und diejenigen mit A[1]=-1durch Negieren in eine Eins-zu-Eins-Entsprechung gebracht werden können A. Ebenso können wir das erste Element Bals nicht negativ festlegen .
  • jetzt mit beschneiden. Sie müssten herumspielen, um N_MAXzu sehen, welche Punktzahl auf Ihrem Computer erzielt werden kann. Es könnte umgeschrieben werden, um N_MAXautomatisch eine geeignete durch binäre Suche zu finden, aber scheint unnötig? Hinweis: Wir müssen den Bereinigungszustand erst überprüfen, wenn N_MAX / 2wir ihn erreichen , damit wir durch Iteration in zwei Phasen ein wenig schneller werden können. Ich habe mich jedoch aus Gründen der Einfachheit und Code-Sauberkeit dagegen entschieden.
Mitch Schwartz
quelle
1
Das ist eine wirklich gute Antwort! Können Sie erklären, was Sie in Ihrer Beschleunigung getan haben?
@Lembik Danke :) Eine Erklärung sowie eine weitere kleine Optimierung wurden hinzugefügt und Python3-kompatibel gemacht.
Mitch Schwartz
Auf meinem Computer habe ich N=57für die erste Version und N=75für die zweite.
kirbyfan64sos
Ihre Antworten waren großartig. Es ist nur so, dass Min_25s Antwort noch mehr war :)
5

Python

Mit Min_25s Idee des zufälligen Gehens konnte ich zu einer anderen Formel gelangen:

p (n) = \ begin {Fälle} \ frac {\ sum _ {i = 0} ^ {\ lfloor n / 2 \ rfloor} \ binom {2i} {i} ^ 2 \ binom {n} {2i} 4 ^ {n-2i}} {8 ^ n} & n \ text {ungerade} \ \ frac {\ binom {n} {n / 2} ^ 2 + \ sum _ {i = 0} ^ {\ lfloor n / 2 \ rfloor} \ binom {2i} {i} ^ 2 \ binom {n} {2i} 4 ^ {n-2i}} {8 ^ n} & n \ text {gerade} \ \ end {Fälle}

Hier ist eine Python-Implementierung, die auf Min_25 basiert:

from time import*
from itertools import*

def main():
    def binom(n, k):
        return facts[n]/(facts[k]*facts[n-k])

    def p(n):
        numer=0
        for i in range(n/2+1):
            t=binom(2*i,i)
            t*=t
            t*=binom(n,2*i)
            t<<=2*(n-2*i)
            numer+=t
        if not n&1:
            numer+=t
        e=(numer&-numer).bit_length()-1
        numer>>=e
        denom=1<<(3*n-e)
        return numer, denom

    facts=[1]
    time_limit=time()+10

    for i in count(1):
        facts.append(facts[-1]*i)

        n,d=p(i)

        if time()>time_limit:
            break

        print("%d %d/%d"%(i,n,d))

main()

Erklärung / Beweis:

Zuerst lösen wir ein verwandtes Zählproblem, wo wir es zulassen A[n+1] = -A[1]; Das heißt, das zusätzliche Element, mit dem verkettet ist, Akann 1oder -1unabhängig vom ersten Element sein. Wir müssen also nicht verfolgen, wie oft es A[i] = A[i+1]vorkommt. Wir haben den folgenden zufälligen Spaziergang:

Von können (x,y)wir zu (x+1,y+1)[1 Weg], (x+1,y-1)[1 Weg], (x-1,y+1)[1 Weg], (x-1,y-1)[1 Weg], (x,y)[4 Wege] übergehen.

wo xund ystehen für die beiden Punktprodukte, und wir zählen die Anzahl der Wege, um schrittweise von (0,0)nach (0,0)zu gelangen n. Diese Zählung würde dann mit multipliziert 2, um die Tatsache zu berücksichtigen, dass Amit 1oder beginnen kann -1.

Wir bezeichnen das Bleiben (x,y)als Nullbewegung .

Wir iterieren über die Anzahl der Züge ungleich Null i, die gerade sein muss, um zurück zu kommen (0,0). Horizontale und vertikale Bewegungen bilden zwei unabhängige eindimensionale Zufallsbewegungen, die gezählt werden können C(i,i/2)^2, wobei der C(n,k)Binomialkoeffizient ist. (Bei einem Spaziergang mit kSchritten nach links und nach krechts gibt es C(2k,k)Möglichkeiten, die Reihenfolge der Schritte zu wählen.) Zusätzlich gibt es C(n,i)Möglichkeiten, die Bewegungen zu platzieren und die 4^(n-i)Nullbewegungen auszuwählen. So bekommen wir:

a(n) = 2 * sum_{i in (0,2,4,...,n)} C(i/2,i)^2 * C(n,i) * 4^(n-i)

Nun müssen wir zum ursprünglichen Problem zurückkehren. Definieren Sie ein zulässiges Paar (A,B), das konvertierbar sein soll , wenn es Beine Null enthält. Definieren Sie ein Paar so (A,B), dass es fast zulässig ist, wenn A[n+1] = -A[1]und die beiden Punktprodukte beide Null sind.

Lemma: Für eine gegebene Zeit nstimmen die fast zulässigen Paare eins zu eins mit den konvertierbaren Paaren überein.

Wir können ein reversibles Paar (reversibel) (A,B)in ein fast zulässiges Paar umwandeln, indem wir (A',B')negieren A[m+1:]und B[m+1:]wo mist der Index der letzten Null in B. Die Überprüfung hierfür ist unkompliziert: Wenn das letzte Element von BNull ist, müssen wir nichts tun. Andernfalls können wir, wenn wir das letzte Element von negieren, das letzte Element von Anegieren B, um den letzten Term des verschobenen Punktprodukts beizubehalten. Dies negiert jedoch den letzten Wert des nicht verschobenen Punktprodukts, sodass wir dies beheben, indem wir das vorletzte Element von negieren A. Aber dann wirft dies den vorletzten Wert des verschobenen Produkts ab, sodass wir das vorletzte Element von negieren B. Und so weiter, bis ein Nullelement erreicht ist B.

Jetzt müssen wir nur zeigen, dass es keine fast zulässigen Paare gibt, für die Bkeine Null enthalten ist. Damit ein Punktprodukt gleich Null ist, müssen wir die gleiche Anzahl 1und -1Begriffe haben, die aufgehoben werden sollen. Jeder -1Begriff besteht aus (1,-1)oder (-1,1). Die Parität der Anzahl -1dieser Vorkommen ist also entsprechend festgelegt n. Wenn das erste und das letzte Element Aunterschiedliche Vorzeichen haben, ändern wir die Parität, sodass dies unmöglich ist.

Also bekommen wir

c(n) = a(n)/2 if n is odd, else a(n)/2 + C(n,n/2)^2

p(n) = c(n) / 8^n

Dies ergibt die obige Formel (Neuindizierung mit i' = i/2).

Update: Hier ist eine schnellere Version mit der gleichen Formel:

from time import*
from itertools import*

def main():
    time_limit=time()+10

    binoms=[1]
    cb2s=[1]
    cb=1

    for n in count(1):
        if n&1:
            binoms=[a+b for a,b in zip([0]+binoms,binoms)]
        else:
            binoms=[a+b for a,b in zip([0]+binoms,binoms+[binoms[-1]])]
            cb=(cb<<2)-(cb+cb)/(n/2)
            cb2s.append(cb*cb)

        numer=0
        for i in xrange(n/2+1):
            t=cb2s[i]*binoms[min(2*i,n-2*i)]
            t<<=2*(n-2*i)
            numer+=t
        if not n&1:
            numer+=t
        e=(numer&-numer).bit_length()-1
        numer>>=e
        denom=1<<(3*n-e)

        if time()>time_limit:
            break

        print("%d %d/%d"%(n,numer,denom))

main()

Optimierungen implementiert:

  • Inline-Funktion p(n)
  • Verwenden Sie die Wiederholung für Binomialkoeffizienten C(n,k)mitk <= n/2
  • Verwenden Sie die Wiederholung für zentrale Binomialkoeffizienten
Mitch Schwartz
quelle
Nur damit Sie wissen, p(n)muss es keine stückweise Funktion sein. Im Allgemeinen können f(n) == {g(n) : n is odd; h(n) : n is even}Sie dann schreiben f(n) == (n-2*floor(n/2))*g(n) + ((n+1)-2*(floor((n+1)/2)))*h(n)oder verwenden, n mod 2anstatt (n-2*floor(n/2)). Siehe hier
mbomb007
1
@ mbomb007 Das ist offensichtlich und uninteressant.
Mitch Schwartz
3

Erklärung der Min_25-Formel

Min_25 hat einen großartigen Beweis veröffentlicht, aber es hat eine Weile gedauert, bis er folgte. Dies ist eine Erklärung, die zwischen den Zeilen eingefügt werden muss.

a (n, m) gibt die Anzahl der Möglichkeiten an, A so zu wählen, dass A [i] = A [i + 1] m mal ist. Die Formel für a (n, m) entspricht a (n, m) = {2 * (n wähle m) für nm gerade; 0 für ungerade nm.} Es ist nur eine Parität zulässig, da A [i]! = A [i + 1] gerade oft auftreten muss, damit A [0] = A [n]. Der Faktor 2 ergibt sich aus der anfänglichen Wahl A [0] = 1 oder A [0] = -1.

Sobald die Anzahl von (A [i]! = A [i + 1]) auf q festgelegt ist (in der c (n) -Formel mit i bezeichnet), wird sie in zwei 1D-Zufallsläufe der Länge q und nq aufgeteilt. b (m) ist die Anzahl der Wege, um einen eindimensionalen zufälligen Spaziergang von m Schritten zu machen, der an der Stelle endet, an der er begonnen hat, und hat eine Chance von 25%, sich nach links zu bewegen, eine Chance von 50%, still zu bleiben, und eine Chance von 25% nach rechts bewegen. Ein offensichtlicherer Weg, die Erzeugungsfunktion anzugeben, ist [x ^ m] (1 + 2x + x ^ 2) ^ n, wobei 1, 2x und x ^ 2 links, keine Bewegung bzw. rechts darstellen. Aber dann ist 1 + 2x + x ^ 2 = (x + 1) ^ 2.

Feersum
quelle
Ein weiterer Grund, PPCG zu lieben! Vielen Dank.
2

C ++

Nur eine Portierung der (ausgezeichneten) Python-Antwort von Mitch Schwartz. Der primäre Unterschied ist , dass ich verwendet 2zur Darstellung -1für die aVariable und tat etwas ähnliches für b, die mir erlaubt , eine Anordnung zu verwenden. Mit Intel C ++ mit habe -O3ich N=141! Meine erste Version bekam N=140.

Dies verwendet Boost. Ich habe eine parallele Version ausprobiert, bin aber auf Probleme gestoßen.

#include <boost/multiprecision/gmp.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/rational.hpp>
#include <boost/chrono.hpp>
#include <boost/array.hpp>
#include <iostream>
#include <utility>
#include <map>

typedef boost::multiprecision::mpz_int integer;
typedef boost::array<boost::array<std::map<int, std::map<int, integer> >, 3>, 2> array;
typedef boost::rational<integer> rational;

int main() {
    BOOST_AUTO(T, boost::chrono::high_resolution_clock::now());

    int N = 1;
    integer n = 1;
    array* Y = new array, *X = NULL;
    (*Y)[1][0][0][0] = 1;
    (*Y)[1][1][1][0] = 1;

    while (boost::chrono::high_resolution_clock::now() < T+boost::chrono::seconds(10)) {
        std::cout << N << " " << rational(n, boost::multiprecision::pow(integer(8), N)/4) << std::endl;
        ++N;
        delete X;
        X = Y;
        Y = new array;
        n = 0;

        for (int a=0; a<2; ++a)
            for (int b=0; b<3; ++b)
                for (BOOST_AUTO(s, (*X)[a][b].begin()); s != (*X)[a][b].end(); ++s)
                    for (BOOST_AUTO(t, s->second.begin()); t != s->second.end(); ++t) {
                        integer c = t->second;
                        int d = b&2 ? -1 : b, e = a == 0 ? -1 : a;

                        if (s->first == -1 && t->first+d+e == 0) n += c;
                        (*Y)[a][1][s->first+1][t->first+d] += c;

                        if (s->first == 1 && t->first-d+e == 0) n += c;
                        (*Y)[a][1][s->first-1][t->first-d] += c;

                        if (s->first == 1 && t->first+d-e == 0) n += c;
                        (*Y)[a][2][s->first-1][t->first+d] += c;

                        if (s->first == -1 && t->first-d-e == 0) n += c;
                        (*Y)[a][2][s->first+1][t->first-d] += c;

                        c *= 2;

                        if (s->first == 0 && t->first+d == 0) n += c;
                        (*Y)[a][0][s->first][t->first+d] += c;

                        if (s->first == 0 && t->first-d == 0) n += c;
                        (*Y)[a][0][s->first][t->first-d] += c;
                    }
    }

    delete X;
    delete Y;
}
kirbyfan64sos
quelle
Dies muss g++ -O3 kirbyfan64sos.cpp -o kirbyfan64sos -lboost_system -lboost_timer -lboost_chrono -lrt -lgmpkompiliert werden. (Danke an aditsu.)