<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>muvik-multigrid &#187; Rekursion</title>
	<atom:link href="http://www.muvik.de/tag/rekursion/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.muvik.de</link>
	<description>open source - engineering - programming</description>
	<lastBuildDate>Wed, 28 Jul 2010 07:56:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Projecteuler: Lösung zu Problem 2</title>
		<link>http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/</link>
		<comments>http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 10:49:44 +0000</pubDate>
		<dc:creator>Viktor Müller</dc:creator>
				<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Projecteuler]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rekursion]]></category>

		<guid isPermaLink="false">http://www.muvik.de/?p=177</guid>
		<description><![CDATA[Die &#8220;Lösungen in Projecteuler&#8221;-Serie geht mit dem zweiten Teil und dem zweiten Problem weiter. Heute stelle ich wieder kurz das Problem vor und einige kleine Statistiken aus Projecteuler.net-Seite und dann gibt es zunächst eine straight-forward Lösung und zwei alternative Ansätze, die eventuell etwas schneller oder eleganter sind. Problemvorstellung Das zweite Problem von Projecteuler.net dreht sich [...]]]></description>
			<content:encoded><![CDATA[<p><img class="cat-img-wide" title="Projecteuler: Lösungen mit Python und C++" src="http://muvik.de/categorie_images/projecteuler_serie_start.gif" alt="Projecteuler: Lösungen mit Python und C++" width="443" height="98" /></p>
<p class="preview">Die &#8220;Lösungen in Projecteuler&#8221;-Serie geht mit dem zweiten Teil und dem zweiten Problem weiter. Heute stelle ich wieder kurz das Problem vor und einige kleine Statistiken aus Projecteuler.net-Seite und dann gibt es zunächst eine straight-forward Lösung und zwei alternative Ansätze, die eventuell etwas schneller oder eleganter sind.</p>
<p><span id="more-177"></span></p>
<h3>Problemvorstellung</h3>
<p>Das zweite Problem von Projecteuler.net dreht sich um eine Zahlenfolge, die bei allen Mathematik- und Informatiklehrern beliebt zu sein scheint. Es handelt sich dabei um die Fibonacci-Folge, eine unendliche Folge von Zahlen, die sich jeweils aus den zwei vorhergehenden Zahlen durch Addition ergeben.</p>
<p>Im folgenden Beispiel beginnt die Fibonacci-Folge mit zwei Einsen:<br />
<code class="bash">1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 ...</code></p>
<p>Ein Herr Fibonacci hat der Legende nach versucht, eine ideal wachsende Kaninchenpopulation damit zu beschreiben. Er ist von zwei Kaninchen ausgegangen und ist auf diese Zahlenfolge mit folgenden Regeln gekommen:</p>
<ul>
<li>das Spiel beginnt mit einem Kaninchenpärchen</li>
<li>pro Zyklus wirft jedes geschlechtsreife Pärchen ein weiteres Pärchen</li>
<li>jedes Pärchen wird im zweiten Zyklus geschlechtsreif</li>
<li>kein Tier stirbt, kein Tier kommt zusätzlich hinzu</li>
</ul>
<p>Wendet man die Regeln an, so lebt im ersten Zyklus ein Pärchen. Im zweiten Zyklus leben schon 2 Pärchen, aber nur eines ist geschlechtsreif und wirft im dritten Zyklus ein weiteres Pärchen. Im vierten Zyklus werden zwei weitere Pärchen geworfen, weil es bereits zwei geschlechtsreife Pärchen gibt, das erste und das zweite Pärchen, welches inzwischen im zweiten Zyklus lebt. Auf diese Weise ergibt sich anschaulich die Fibonacci-Folge. Vielleicht lieben es die Lehrer deswegen so sehr <img src='http://www.muvik.de/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .</p>
<p>Etwas mathematischer ausgedrückt sieht es so aus:</p>
<img src='http://s.wordpress.com/latex.php?latex=a_%7B1%7D%3D1%20%5Cnewline%20a_%7B2%7D%3D2%20%5Cnewline%20%20a_%7Bi%7D%20%3D%20a_%7Bi-2%7D%2Ba_%7Bi-1%7D&#038;bg=ffffff&#038;fg=000000&#038;s=1' alt='a_{1}=1 \newline a_{2}=2 \newline  a_{i} = a_{i-2}+a_{i-1}' title='a_{1}=1 \newline a_{2}=2 \newline  a_{i} = a_{i-2}+a_{i-1}' class='latex' />
<p>Damit haben wir das zweite Problem von Projecteuler.net etwas eingegrenzt und das Verständnis für die Fibonacci-Folge bildlich untermauert.</p>
<p>Doch worum geht es in dem Problem?</p>
<p><strong>In der zweiten Aufgabe sollen wir alle Zahlen der Fibonacci-Folge, die kleiner als vier Millionen und gleichzeitig gerade sind, addieren.</strong></p>
<p>Das war es schon.</p>
<p>Die Aufgabe gehört genauso, wie die erste zu den einfacheren Problemen. Zum heutigen Zeitpunkt haben 73397 der derzeit 95331 registrierten Hobbymathematiker diese Aufgabe gelöst, das sind immerhin stolze 77%.</p>
<h3>Problemeingrenzung</h3>
<p>Um der Herausforderung dieses Problems etwas auf die Schliche zu kommen, habe ich mir einfach alle Zahlen der Fibonacci-Folge ausgeben lassen, die kleiner als 4000000 sind. Dazu habe ich folgende kleine Funktion geschrieben:</p>
<pre class="brush:python">def print_fibos(N):
    i = 1;

    fibs = np.zeros(1)
    fibs[0] = 1
    fibs = np.append(fibs,[2.],axis=0)
    while (fibs[i]+fibs[i-1])</pre>
<p>Die Ausgabe zeigt genau 32 Zahlen. Würde man alle Zahlen addieren wollen, dann wären das 31 Additionen von Ganzzahlen, was nicht wirklich aufwendig ist. Deswegen denke ich, dass es eher sinnvoll ist, die Lösung dahingehend zu optimieren, dass möglichst wenige Tests durchgeführt werden müssen, ob eine Zahl gerade ist oder nicht.</p>
<h3>Problemlösung</h3>
<p>Wie bereits angekündigt stelle ich zunächst eine straight-forward Lösung vor. Hierbei geht Python alle Fibonacci-Zahlen durch und überprüft, ob sie kleiner als die Grenze von 4000000 ist und ob sie gerade ist. Sind beide Bedingungen erfüllt, so wird die Zahl zu einem Zähler addiert.<br />
So sieht das in Python-Code aus:</p>
<pre class="brush:python">import time as t
import numpy as np

def straight_forward(N):
    count  = 2;
    first  = 2;
    second = 3;
    next   = 0;

    while next &lt; N:
        next = first+second;
        first = second;
        second = next;

        if next%2 == 0:
            count = count + next

    return count;

# max. fibo
N = 4000000

print_fibos(N);

t0 = t.time();
erg = straight_forward(N);
tn = t.time();

print("The straight-forward method needed %.15f seconds.\nThe sum is: %12i" %(tn-t0,erg));</pre>
<p>Die Funktion gibt auf Anhieb die richtige Lösung von 4613732 aus.</p>
<h3>Lösungsanalyse</h3>
<p>In dem Code der straight-forward Lösung habe ich bereits die Zeitmessung mit eingebaut. Die Ausgabe des kleinen Programms liefert:</p>
<p><code class="bash">The straigt-forward method needed 0.000010013580322 seconds.<br />
The sum is:      4613732</code><br />
Ehrlich gesagt, ist die Ausgabe der Zeit in diesem Fall wohl eher nicht sehr zuverlässig. Mir geht es jedoch mehr um die Tendenz, weniger um den absoluten Wert, daher ist es ok.</p>
<p>Also hat die straight-forward Lösung in einer Zeit von 10 Mikrosekunden 10 Zahlen addiert und 31 Zahlen auf die Teilbarkeit durch zwei geprüft. Da die Aufgabe noch recht leicht ist, muss es ja auch besser gehen. Darum geht es im nächsten Abschnitt.</p>
<h3>alternative Lösung</h3>
<p>Die Problemeingrenzung hat uns gezeigt, dass es gilt, die Teilbarkeitstest durch zwei so selten wie nur möglich durchzuführen sind. Am Besten wären gar keine Tests. </p>
<p>Schauen wir uns die Folge der geraden Fibonacci-Zahlen näher an:<br />
<code class="bash">1, <strong>2</strong>, 3, 5,<strong> 8</strong>, 13, 21, <strong>34</strong>, 55, 89, <strong>144</strong>, 233 ...</code><br />
Es wird deutlich, dass ab der &#8220;2&#8243; jede dritte Zahl eine gerade Zahl ist. Folglich müssen auch nur diese summiert werden. Aus diesen Überlegungen hat sich dann folgender Code ergeben:</p>
<pre class="brush:python">import time as t
import numpy as np

def only_even(N):
    count = 2;
    a = 1;
    b = 2;
    next = 0;

    while count < N:
        next = 2*a+3*b
        a = 2*b+a
        b = next
        count = count + next;
    return count;

N=4000000;

t0 = t.time();
erg = only_even(N);
tn = t.time();

print("The only_even method needed %.15f seconds.\nThe sum is: %12i" %(tn-t0,erg));
</pre>
<p>Die Anweisung zur Berechnung der nächsten gerade Fibonacci-Zahl ergibt sich aus folgender Betrachtung:</p>
<img src='http://s.wordpress.com/latex.php?latex=next%20%3D%20a%20%2B%20b%3B%20%5C%3A%20a%5E%7B%27%7D%3Db%3B%5C%3A%20b%5E%7B%27%7D%3Dnext%20%5Cnewline%20next%5E%7B%27%7D%20%3D%20a%5E%7B%27%7D%20%2B%20b%5E%7B%27%7D%3B%20%5C%3A%20a%5E%7B%27%27%7D%3Db%5E%7B%27%7D%3B%5C%3A%20b%5E%7B%27%27%7D%3Dnext%5E%7B%27%27%7D%20%5Cnewline%20next%5E%7B%27%27%7D%20%3D%20a%5E%7B%27%27%7D%20%2B%20b%5E%7B%27%27%7D%3B%20%5C%3A%20a%5E%7B%27%27%27%7D%3Db%5E%7B%27%27%7D%3B%5C%3A%20b%5E%7B%27%27%27%7D%3Dnext%5E%7B%27%27%27%7D%20%5Cnewline&#038;bg=ffffff&#038;fg=000000&#038;s=1' alt='next = a + b; \: a^{&#039;}=b;\: b^{&#039;}=next \newline next^{&#039;} = a^{&#039;} + b^{&#039;}; \: a^{&#039;&#039;}=b^{&#039;};\: b^{&#039;&#039;}=next^{&#039;&#039;} \newline next^{&#039;&#039;} = a^{&#039;&#039;} + b^{&#039;&#039;}; \: a^{&#039;&#039;&#039;}=b^{&#039;&#039;};\: b^{&#039;&#039;&#039;}=next^{&#039;&#039;&#039;} \newline' title='next = a + b; \: a^{&#039;}=b;\: b^{&#039;}=next \newline next^{&#039;} = a^{&#039;} + b^{&#039;}; \: a^{&#039;&#039;}=b^{&#039;};\: b^{&#039;&#039;}=next^{&#039;&#039;} \newline next^{&#039;&#039;} = a^{&#039;&#039;} + b^{&#039;&#039;}; \: a^{&#039;&#039;&#039;}=b^{&#039;&#039;};\: b^{&#039;&#039;&#039;}=next^{&#039;&#039;&#039;} \newline' class='latex' />
<p>Setzt man nun von unten nach oben die jeweiligen Variablen ein, so ergibt sich die oben aufgeführte Formel.</p>
<p>Doch welche Vorteile bringt diese Lösung? Folgende Ausgabe erhält man beim Ausführen:<br />
<code class="bash">The only_even method needed 0.000007867813110 seconds.<br />
The sum is:      4613732</code> Also haben wir damit etwas weniger Wartezeit und sind somit effizienter. </p>
<p>Ok, das ist schon besser, aber ich war noch nicht zufrieden und habe noch eine Lösung ausgetestet:</p>
<h3>alternative Lösung 2</h3>
<p>Mit der zweite alternative Lösung habe ich einen rekursiven Ansatz verfolgt:</p>
<pre class="brush:python">import time as t
import numpy as np
def rec_fibo(a,b,N):
    next = 2*a + 3*b;
    if (next < N):
        return next + rec_fibo(2*b+a,next,N);
    else:
        return 0;

t0 = t.time();
erg = rec_fibo(1,2,N);
tn = t.time();

print("The recursive method needed %.15f seconds.\nThe sum is: %12i" %(tn-t0,erg));
</pre>
<p>Wie du bestimmt festgestellt hast, verwendet auch die rekursive Lösung keine Gradheitsüberprüfung der Fibonacci-Zahlen. Hier habe ich genauso, wie bei der ersten alternativen Lösung nur die geraden Zahlen betrachtet.</p>
<p>Die Rekursion bietet sich oft für Probleme wie dieses an. Es ergibt meist eine recht elegante und kurze Lösung, die aber nicht zwangsläufig auch weniger Rechenzeit benötigt, wie die Ausgabe zeigt:<br />
<code class="bash">The straigt-forward method needed 0.000010013580322 seconds.<br />
The sum is:      4613732<br />
The only_even method needed 0.000007867813110 seconds.<br />
The sum is:      4613732<br />
The recursive method needed 0.000009059906006 seconds.<br />
The sum is:      4613730</code></p>
<p>Zusammengefasst ist die einfache Lösung ohne Gradheitsüberprüfung die schnellste, jedoch sind die Zeiten bei dieser Dimension des Problems mit Vorsicht zu genießen, sie sind ziemlich klein.</p>
<h3>Fazit</h3>
<p>Damit wäre ich am Ende meiner Lösungsvorstellung des zweiten Projecteuler.net Problems. Diesmal gab es wieder eine Neuerung, die bisher in der Form in meinem Weblog noch nicht vorkam: die Rekursion.</p>
<p>Jetzt ist wieder deine Meinung gefragt: Was hat dir gefallen, was nicht und was würdest du mir als Tipp für die nächste Folge "Lösungen mit Python und C++" mitgeben?</p>
<p><a href="http://partners.webmasterplan.com/click.asp?ref=515746&site=6989&type=text&tnb=1" target="_blank">
Deine Stadt - Dein Preis</a><br />Mit CityDeal und vielen Anderen
den Preis drücken!<br /><img src="http://banners.webmasterplan.com/view.asp?ref=515746&site=6989&type=text&tnb=1&js=1" BORDER="0" WIDTH="1" HEIGHT="1" /></p>
<hr />
<p><small>© Muvik for <a href="http://www.muvik.de">muvik-multigrid</a>, 2010. |
<a href="http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/">Permalink</a> |
<a href="http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/#comments">keine Kommentare</a> |
Teile es mit deinen Freunden:
<a href="http://del.icio.us/post?url=http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/&title=Projecteuler: Lösung zu Problem 2">del.icio.us</a>
<a href="http://www.mister-wong.de/addurl/?bm_url=http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/&title=Projecteuler: Lösung zu Problem 2">MisterWong</a>
<a href="http://twitter.com/home?status=http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/&title=Projecteuler: Lösung zu Problem 2">Twitter</a>
<br/>
Tags: <a href="http://www.muvik.de/tag/projecteuler/" rel="tag">Projecteuler</a>, <a href="http://www.muvik.de/tag/python/" rel="tag">Python</a>, <a href="http://www.muvik.de/tag/rekursion/" rel="tag">Rekursion</a><br/>
</small></p>]]></content:encoded>
			<wfw:commentRss>http://www.muvik.de/2010/02/17/projecteuler-loesung-zu-problem-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

