Diskussion: Pi möglichst schnell berechnen

OP #5797438
Lesenswert?

Hallo zusammen

Ausgangslage:
Es soll die Zahl Pi möglichst schnell auf die 5. Nachkommastelle genau 
berechnet bzw. angenähert werden.

Ich habe einige Ideen, so z.B. die Ramanujan methode
http://numbers.computation.free.fr/Constants/Pi/piramanujan.html

Aber ich kenne das Forum nun schon länger und es gibt hier immer wieder 
sehr spannende Ideen. Deshalb würde ich mich über eine offene Diskussion 
freuen.

Es ist klar, dass in der Praxis dies eigentlich nicht gemacht wird, 
sondern dafür eine Kostante verwendet wird.

Achja, Zielplatform: Atxmega128.

Danke schonmal
Gast #5797450
Lesenswert?

[K]ein Sohn [des] Admins (frei nach Lk 3,33) schrieb im Beitrag 
#5797448:
> Die Fortran Gemeinde machtπ=4∗arcsin1\pi=4*\arcsin{1}

Schuldigung, es ist der Arcustangens.
Moderator #5797457
Lesenswert?

[K]ein Sohn [des] Admins (frei nach Lk 3,33) schrieb im Beitrag 
#5797450:
> Arcustangens

Ja, damit geht es sehr schnell:

1
#include <math.h>
2

3
float pi;
4

5
int main(void) {
6
  pi = 4 * atan(1);
7
}


Der Compiler liefert:

1
main:
2
  ldi r24,lo8(-37)
3
  ldi r25,lo8(15)
4
  ldi r26,lo8(73)
5
  ldi r27,lo8(64)
6
  sts pi,r24
7
  sts pi+1,r25
8
  sts pi+2,r26
9
  sts pi+3,r27
10
  ldi r25,0
11
  ldi r24,0
12
  ret

Für nur fünf Nachkommestellen lohnt es sich nicht, sich Gedanken zum
optimalen Algorithmus zu machen. Interessant wird es frühestens bei
ein paar Hunderttausend Nachkommastellen.
Gast #5797943
Lesenswert?

Ich weiß zwar auch nicht, warum der TO das berechnen will, aber 
2*arccos(0) etc. Ist für mich dann eher ein taschenspielertrick, was ja 
auch

Yalu X. schrieb:
> Der Compiler liefert

zeigt. Das ist nahe an "einfach den Kehrwert von 1/Pi".

Oder ging es dem TO eher um Taschenrechner, wo mangels Tasten die 
Konstanten so abruft? Also z.b. e^1 wenn man e braucht.
Gast #5798139
Lesenswert?

Hab mal was rumgespielt und mit den Kettenbrüchen von Lambert ist Pi mit 
einem 10-fach Kettenbruch mit maximaler float Genauigkeit und mit einem 
22-fach Kettenbruch mit maximaler double Genauigkeit berechenbar.

Und dazu noch extrem einfach zu implementieren:
1
double Kettenbruch( int n_max ) {
2

3
  int n;
4
  double nenner = 2 * n_max - 1;
5
    
6
  for ( n = n_max - 1; n > 0; n-- ) nenner = 2 * n - 1 + n * n / nenner;
7

8
  return nenner;
9

10
}
11

12
double pi( void ) {
13

14
  return ( 4 / Kettenbruch( 22 ) );
15

16
}
OP #5798264
Lesenswert?

Vielen Dank für all eure, teils sehr interessanten Ansätze!

Nochmals kurz zum Sinn bzw. Unsinn.
Es geht nicht darum, dies für etwas "produktives" einzusetzen.

Es geht mehr darum, sich mit Mathematik und den eventuellen 
Vereinfachungen zu beschäftigen.

Sich mit möglichen Optimierungen oder Stolpperfallen bei uCs 
auseinanderzusetzen.

Natürlich möchte ich dann auch einen Algorithmus als "Beweis" 
implementieren.
Dies aber mehr als spielerei.

Natürlich würde ich bei etwas "produktiven" die benötigte Genauigkeit 
auf einem PC rechnen lassen oder aus dem Netz holen und als Konstante 
ablegen.
Gast #5801377
Lesenswert?

Harald W. schrieb:
> Vielleicht reicht ja auch dieser "gesetzliche" Wert:
> https://de.wikipedia.org/wiki/Indiana_Pi_Bill

PI=4, stimmt doch? Die Distanz zwischen 2 Punkten berechnen, einfach die 
X und Y Distanz addieren, keine nervigen Wurzeln und Quadrate nötig! Ein 
Kreis zeichnen ist auch viel einfacher, 4 Linien und man ist fertig! Und 
es gibt auch nicht immer nur den einen schnellsten Weg, der zum Ziel 
führt, sondern ein ganzes Rechteck an schnellsten wegen! Die 
Manhattan-Metrik ist der Euklidischen Geometrie massiv überlegen!!!

https://en.wikipedia.org/wiki/Taxicab_geometry
#5801828
Lesenswert?

Tim T. schrieb:
> Nico W. schrieb:
>> Ohne Division wenn man Integermathematik ausnutzen möchte.
>>
1
201 >> 6
>
> = 3
>
> Tolle Wurst^^

der win Rechner meint: 3,14062

auch eher schwächer auf 5 Nachkommastellen als

Bernd schrieb:
>
1
> 
2
> 
3
>               -----
4
>  9     --    /  9
5
> --- +    \  /  ---  ~ Pi
6
>  5        \/    5
7
> 
8
> 
9
>

gibt 3,14164 und ist näher an 3,14159

sonst
https://de.wikihow.com/F%C3%A4lschlicherweise-beweisen,-dass-Pi-gleich-3-ist
Gast #5801885
Lesenswert?

Archimedes' Verfahren in Visual Basic

' Erstellt Pi aufgrund des Archimedes-Verfahren
' mit einem 2 ^ 26 Eck.
Private Function Pi() As Double
    Dim a       As Double
    Dim b       As Double

    a = 2 * Sqr(3)
    b = 3

    Do Until a = b
        a = 2  a  b / (a + b)
        b = Sqr(a * b)
    Loop

    Pi = a

End Function
Gast #5801890
Lesenswert?

Archimedes' Verfahren in Visual Basic

' Erstellt Pi aufgrund des Archimedes-Verfahren
' mit einem 2 ^ 26 Eck.
Private Function Pi() As Double
    Dim a       As Double
    Dim b       As Double

    a = 2*Sqr(3)
    b = 3

    Do Until a = b
        a = 2*a*b/(a + b)
        b = Sqr(a*b)
    Loop

    Pi = a

End Function
#5801903
Lesenswert?

Tim T. schrieb:
> Nico W. schrieb:
> Ohne Division wenn man Integermathematik ausnutzen möchte.
>
> 201 >> 6
>
> = 3
>
> Tolle Wurst^^

Ein bisschen Grips wird beim Anwenden davon erwartet. Würde ich bei 
Fließkommarechnungen auch nicht einsetzen. Daher auch der Hinweis auf 
Integermathematik.


Bei Fixedpoint geht das dann aber Ratzfatz mit einem Fehler unter 0,1%.
Gast #5801911
Lesenswert?

Nico W. schrieb:
>
> Ein bisschen Grips wird beim Anwenden davon erwartet. Würde ich bei
> Fließkommarechnungen auch nicht einsetzen. Daher auch der Hinweis auf
> Integermathematik.
>
>
> Bei Fixedpoint geht das dann aber Ratzfatz mit einem Fehler unter 0,1%.

Wie willst du das bitte sinnvoll einsetzen? Ich sehe da so garkeine 
Möglichkeit.
Gast #5801914
Lesenswert?

Wofram_Draht schrieb:
> Archimedes' Verfahren in Visual Basic
>
> ' Erstellt Pi aufgrund des Archimedes-Verfahren
> ' mit einem 2 ^ 26 Eck.
> Private Function Pi() As Double
>     Dim a       As Double
>     Dim b       As Double
>
>     a = 2*Sqr(3)
>     b = 3
>
>     Do Until a = b
>         a = 2*a*b/(a + b)
>         b = Sqr(a*b)
>     Loop
>
>     Pi = a
>
> End Function

Dürfte immernoch Faktor 3 langsamer sein als es mit Kettenbrüchen zu 
rechnen.


Ausgleich
der
vielen
Zitatzeilen
#5801967
Lesenswert?

Tim T. schrieb:
>> Bei Fixedpoint geht das dann aber Ratzfatz mit einem Fehler unter 0,1%.
>
> Wie willst du das bitte sinnvoll einsetzen? Ich sehe da so garkeine
> Möglichkeit.

Weil du keine Fixpointrechnung kennst?

Darstellung mit 10bit für die Nachkommastelle:
1
int radius = 2 << 10; // 2048 / (1 << 10) = 2.0
2
int umkreis = 2 * radius * 201 >> 6; // 12864 / (1 << 10) = 12.5625

Dazu das ganze mit normalen floats:
1
float pi = 3.14159f;
2
float radius = 2.0f;
3
float umkreis = 2 * radius * pi; // 12,56636
Gast #5802008
Lesenswert?

leo schrieb:
> Nico W. schrieb:
>> int umkreis = 2  radius  201 >> 6; // 12864 / (1 << 10) = 12.5625
>
> Ja, wenn du dann noch Klammern setzt, funktioniert das auch.
>
> leo

sorry fuer den falschen Einwurf, es wuerde funktionieren, wenn die ints 
lang genug (32 bit) sind.

leo
Moderator #5802037
Lesenswert?

Nico W. schrieb:
> Ohne Division wenn man Integermathematik ausnutzen möchte.
>
> 201 >> 6

Wie bereits geschrieben wurde, geht des so direkt nicht. Man kann aber
auch den Ausdruck 201.0/64 (in Floating-Point) ohne Division und
Multiplikation berechnen:

1
#include <stdio.h>
2
#include <stdint.h>
3
#include <math.h>
4

5
float z = 201.0;  // global, um Berechnung zur Laufzeit zu erzwingen
6

7
int main(void) {
8
  float pi;
9

10
  // pi = z / 64
11

12
# if defined __STDC_IEC_559__ || defined __AVR_ARCH__
13
    union { float f; uint8_t c[4]; } u = { z };   // u.f = z;
14
#   if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__  
15
      u.c[3] -= 3;                                // u.f /= (1<<(2*3));
16
#   elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
17
      u.c[0] -= 3;                                // u.f /= (1<<(2*3));
18
#   else
19
#     error cannot determine endianess
20
#   endif
21
    pi = u.f;                                     // pi = u.f;
22
# else
23
    pi = ldexp(z, -6);                            // pi = z / (1<<6);
24
# endif
25

26
  printf("%f\n", pi);
27
}

Stellt der Compiler float-Zahlen gemäß ISO/IEC/IEEE 60559 (IEEE 754)
dar, reduziert sich die Division auf eine einfache 8-Bit-Subtraktion.
Sonst kann dafür auch die ldexp-Funktion genutzt werden, die allerdings
auch potentielle Überläufe und denormalisierte Zahlen berücksichtigt
(was hier nicht nötig ist) und deswegen weniger effizient ist.
#5802140
Lesenswert?

leo schrieb:
> sorry fuer den falschen Einwurf, es wuerde funktionieren, wenn die ints
> lang genug (32 bit) sind.

Das ist allgemein bei Fixedpoint immer zu beachten und kann einem auf 
die Füße fallen.

Yalu X. schrieb:
> Wie bereits geschrieben wurde, geht des so direkt nicht.

Mir ging es um den Verzicht um floats und co.
1
#include <stdio.h>
2

3
int main(void) {
4
    int pi = 201 << 4;
5
    int dec = pi >> 10;
6
    int frac = (pi - (dec << 10)) * 976562; // 0,000976562 = 1 / 1024
7

8
    printf("%d.%09d\n", dec, frac);
9
}
Gast #5802189
Lesenswert?

>> Bei Fixedpoint geht das dann aber Ratzfatz mit einem Fehler unter 0,1%.
>
> Wie willst du das bitte sinnvoll einsetzen? Ich sehe da so garkeine
> Möglichkeit.

Pi selbst ausrechnen, ist ja sinnlos.   Es kommt aber häufig (meist?) 
als Faktor vor und dann kommt man mit Brüchen (x*22/7, x*355/113, 
x*201/64, usw) weiter als mit x*3.  Wie weit, kommt drauf an, wieviele 
Bits man für das Zwischenergebnis übrig hat - einige Sprachen (CPUs?) 
bietet dafür sogar extra eine muldiv-Funktion mit doppelt genauem 
Zwischenergebnis an.
Gast #5802269
Lesenswert?

foobar schrieb:
>>> Bei Fixedpoint geht das dann aber Ratzfatz mit einem Fehler unter 0,1%.
>>
>> Wie willst du das bitte sinnvoll einsetzen? Ich sehe da so garkeine
>> Möglichkeit.
>
> Pi selbst ausrechnen, ist ja sinnlos.   Es kommt aber häufig (meist?)
> als Faktor vor und dann kommt man mit Brüchen (x*22/7, x*355/113,
> x*201/64, usw) weiter als mit x*3.  Wie weit, kommt drauf an, wieviele
> Bits man für das Zwischenergebnis übrig hat - einige Sprachen (CPUs?)
> bietet dafür sogar extra eine muldiv-Funktion mit doppelt genauem
> Zwischenergebnis an.

Mein Einwand bezog sich mehr darauf, welche Vorteile das bieten soll. 
Wenn ich Pi als Float Konstante ablege, kostet mich das 4 Byte, als Int 
Operation bin ich ebenfalls ab 4 Byte dabei. Die Genauigkeit als Float 
ist höher, bleibt also nur noch die Geschwindigkeit und da kostet eine 
Float Multiplikation, je nach CPU etwa die 3-fache Zeit wie eine mit 
32-Bit Int, mit FPU noch weniger. Dafür sparst man aber die Verschiebung 
(ok, das geht fix wenn die Zielhardware die nativ auf mindestens 32-Bit 
unterstützt) und sobald man das Endergebnis irgendwann doch als 
richtigen Wert braucht, ist der Geschwindigkeitsvorteil komplett dahin.
Aber selbst wenn nicht am Ende umgewandelt wird, man tauscht nicht 
gerade wenig Genauigkeit gegen einen minimalen Geschwindigkeitsvorteil 
und macht es sich zusätzlich unnötig schwer.
Persönliche Seite #5803189
Lesenswert?

Dumdi D. schrieb:
> Pi in hexadecimal ausrechnen:
>
> https://de.m.wikipedia.org/wiki/Bailey-Borwein-Plouffe-Formel
>
> Eine Berechnung jeder Stelle von Pi ohne die Berechnung der
> vorhergehenden (im 16er System) ist möglich.

...und im Wiki sogar implementiert (C99) und ausführich kommentiert:

4000 Stellen von Pi mit ATtiny2313

Übersetzbar mit einem avr-gcc für ATtiny2313 und Ausgabe via USART, und 
das Programm lässt sich auch ganz normal für einem Host übersetzen und 
ausführen :-)

Eben mal mit avrtest durchlaufen lassen.  Für 100 Nachkommastellen 
(Basis 16) von pi braucht's ca. 38E6 Ticks, für 5 Nachkommstellen also 
(1/20)^2 = 1/400 mal so viel, und für Basis 10 nur das log 10 / log 16 = 
0.83-fache.

Um das Äquivalent von 5 dezimalen Nachkommastellen zu berechnen 
braucht's also ca. 38E6 / 400 * 0.83 ~ 80000 Ticks.  Damit ist es das 
bislang aufwändigste Verfahren — und genau das war vom TO gewünscht :-)
Persönliche Seite #5803346
Lesenswert?

Wofür soll die Geschichte denn sein? Wenn man PI genau berechnen will, 
bringt es nur etwas, wenn man eine höhere G berechnet, die bisher schon 
bekannt ist und selbst die übersteigt, alles, was man braucht.

Solche schlauen iterativen Verfahren brauchen wir doch eigentlich nur 
für Funktionen Y(X), also einem unbekannten Werdt, wie z.B: LOG.
OP #5807490
Lesenswert?

Jürgen S. schrieb:
> Wofür soll die Geschichte denn sein?

Das steht weiter oben im Thread.

Es geht darum, an einem an sich einfachen Beispiel, optimierungen im 
Bereich Mathe und Prozessoren anzuwenden.

Es macht einen unterschied ob man alles mit integer "zu gross" rechner 
oder ob man von beginn an float verwendet.

So auch ob man evtl. einen HW-Multiplier verwendet oder nicht etc...
Gast #5808177
Lesenswert?

Tim T. schrieb:
> Frage schrieb:
>> Wozu braucht man eigentlich die dezimalen Stellen von Pi?
>
> Und warum liegt hier überhaupt Stroh rum?

Zur Erläuterung meiner Frage:

BCD-Arithmetik wird ja nur im kaufmännischen Bereich verwendet.
Und dort braucht man Pi nicht.

Im MINT-Bereich, wo man Pi braucht, rechnet man binär.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren