Forum: Compiler & IDEs Kreiszahl Pi in einer Funktion berechnen oder per #define festlegen?


von Christian W. (christian_w)


Lesenswert?

Hallo zusammen, ich bin neulich über ein Codeschnipsel in einem großen 
Programm gestolpert. Dort wird die Kreiszahl Pi in einer etwa 15 Zeilen 
langen Funktion berechnet, obwohl in der selben Datei die <math.h> 
eingebunden ist, und somit der Zugriff auf "M_PI" möglich wäre. Die 
Funktion liefert als Rückgabetyp einen "long double". Genauer als 20 
Stellen wird's ja deswegen auch nicht, oder? Was ist der Sinn der Sache, 
dass der Programmierer Pi in einer Funktion berechnet, anstatt auf die 
definierte Konstante mit 20 Nachkommastellen zuzugreifen? Ich bin nicht 
dahintergekommen. Hat jemand eine Idee?

von Arduinoquäler (Gast)


Lesenswert?

Christian W. schrieb:
> Hat jemand eine Idee?

Er sah den Wald vor lauter Bäumen nicht und wusste daher
nicht das Pi schon vorkonserviert zur Verfügung steht.

von Micha S. (ernie)


Lesenswert?

Christian W. schrieb:
> Hallo zusammen, ich bin neulich über ein Codeschnipsel in einem großen
> Programm gestolpert. Dort wird die Kreiszahl Pi in einer etwa 15 Zeilen
> langen Funktion berechnet, obwohl in der selben Datei die <math.h>
> eingebunden ist, und somit der Zugriff auf "M_PI" möglich wäre. Die
> Funktion liefert als Rückgabetyp einen "long double". Genauer als 20
> Stellen wird's ja deswegen auch nicht, oder? Was ist der Sinn der Sache,
> dass der Programmierer Pi in einer Funktion berechnet, anstatt auf die
> definierte Konstante mit 20 Nachkommastellen zuzugreifen? Ich bin nicht
> dahintergekommen. Hat jemand eine Idee?

ich schreibe immer "pi = (4 * arctan(-1))", sieht irgendwie viel cooler 
aus als das benutzen einer Konstanten aus math.h :-)

Micha

von Dennis S. (eltio)


Lesenswert?

Ich tippe mal auf mangelnde Kenntnisse der Standard-Bibliothek... :-)

von Karl H. (kbuchegg)


Lesenswert?

Profilierung vor der Freundin?

Das kann man so nicht sagen.
Kommt drauf an, ob er mit einem long double die Auflösung und die 
Genauigkeit überhaupt noch ausfahren kann. Ohne Analyse dessen, wie 
damit gerechnet wird und wie die Fehlerfortpflanzung zuschlägt, ist dazu 
wenig zu sagen.

Mal ganz davon abgesehen, dass es recht witzlos ist, das jedes mal neu 
zu rechnen. Wenn schon, dann bestimmt man sich PI auf die Anzahl der 
Stellen die man haben will oder lädt die sich aus dem Web runter. Noch 
ein #define und gut ists.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Christian W. schrieb:
> Dort wird die Kreiszahl Pi in einer etwa 15 Zeilen langen
> Funktion berechnet, obwohl in der selben Datei die <math.h>
> eingebunden ist, und somit der Zugriff auf "M_PI" möglich wäre.

M_PI wird in math.h auch nicht definiert.  M_PI ist eine 
GNU-Erweiterung, d.h. es kann verwendet werden und wird durch math.h 
verfügbar wenn die Quelle in GNU-C steht.  "Offiziell" ist M_PI aber 
nicht.

> Die Funktion liefert als Rückgabetyp einen "long double".
> Genauer als 20 Stellen wird's ja deswegen auch nicht, oder?
> Was ist der Sinn der Sache, dass der Programmierer Pi in einer
> Funktion berechnet, anstatt auf die definierte Konstante
> mit 20 Nachkommastellen zuzugreifen?

Wenn man den Algorithmus nicht sorgsam auwählt, ist die Näherung 
vermutlich deutlich schlechter als 20 Nachkommastellen und nicht besser 
als 22/7 oder 355/113.

> Ich bin nicht dahintergekommen. Hat jemand eine Idee?

Vermutlich weil der Autor Spaß dran hat.


Micha S. schrieb:
> ich schreibe immer "pi = (4 * arctan(-1))", sieht irgendwie viel
> cooler aus als ...

Dafür auch viel falscher, nämlich um 2π daneben ;-)

von Micha S. (ernie)


Lesenswert?

Johann L. schrieb:

> Micha S. schrieb:
>> ich schreibe immer "pi = (4 * arctan(-1))", sieht irgendwie viel
>> cooler aus als ...
>
> Dafür auch viel falscher, nämlich um 2π daneben ;-)

wer hat das -1 da hingemacht? Sauerei! :-)

von Karl H. (kbuchegg)


Lesenswert?

Micha S. schrieb:
> Johann L. schrieb:
>
>> Micha S. schrieb:
>>> ich schreibe immer "pi = (4 * arctan(-1))", sieht irgendwie viel
>>> cooler aus als ...
>>
>> Dafür auch viel falscher, nämlich um 2π daneben ;-)
>
> wer hat das -1 da hingemacht? Sauerei! :-)

alte Regel: immer eine gerade Anzahl an Vorzeichenfehlern machen!
1
pi = -( 4 * atan(-1) );
:-)

von Christian W. (christian_w)


Lesenswert?

Ok, danke für die schnellen und zahlreichen Antworten.

Fassen wir mal zusammen.

Ich kann also generell am Anfang meiner C-Datei oder in meiner selbst 
erstellten Headerdatei schreiben:
1
#define MY_PI 3.14159265358979323846

...und kann überall da, wo im Programm die Pi-Berechnungs-Funktion 
aufgerufen wird, diese durch "MY_PI" ersetzen, ohne dass sich an der 
Genauigkeit des Ergebnisses (3 Nachkommastellen sind gefordert) etwas 
ändert. Richtig?

Vor allem bei Mikrocontroller-Anwendungen bei einem Takt von 1 MHz finde 
ich generell ein #define besser als eine Berechnungsfunktion für Pi, 
beispielsweise aus Zeitgründen...

Christian.

von Bitflüsterer (Gast)


Lesenswert?

Karl Heinz schrieb:
>...

> alte Regel: immer eine gerade Anzahl an Vorzeichenfehlern machen!

Grins.

von Fpgakuechle K. (Gast)


Lesenswert?

Christian W. schrieb:
> Hallo zusammen, ich bin neulich über ein Codeschnipsel in einem großen
> Programm gestolpert. Dort wird die Kreiszahl Pi in einer etwa 15 Zeilen
> langen Funktion berechnet, obwohl in der selben Datei die <math.h>
> eingebunden ist, und somit der Zugriff auf "M_PI" möglich wäre. Die
> Funktion liefert als Rückgabetyp einen "long double". Genauer als 20
> Stellen wird's ja deswegen auch nicht, oder?

Doch es könnte genauer werden.
Die Floating point units rechnen intern mit einer höheren Genauigkeit 
als die "integer" Einheit. So definiert der Standard IEEE-754 eine 32 
bit genauigkeit und eine extended 40 bit. Bei Datenaustausch muss 
jeweils gerundet werden. Es könnte also sein das bei den define-pi das 
schliesslich im assemblercode über die integer einheit in die floating 
point einheit geladen wird nur 32 bit übergeben werden können, während 
bei der Berechnungsroutine 40 bit genau ermittelt wird.

http://en.wikipedia.org/wiki/Extended_precision#IEEE_754_extended_precision_formats

http://c-faq.com/fp/strangefp.html

Zitat:
" Beware that some machines have more precision available in 
floating-point computation registers than in double values stored in 
memory"

MfG,

von Fpgakuechle K. (Gast)


Lesenswert?

Christian W. schrieb:
> Fassen wir mal zusammen.
>
> Ich kann also generell am Anfang meiner C-Datei oder in meiner selbst
> erstellten Headerdatei schreiben:
>
>
1
#define MY_PI 3.14159265358979323846
>
> ...und kann überall da, wo im Programm die Pi-Berechnungs-Funktion
> aufgerufen wird, diese durch "MY_PI" ersetzen, ohne dass sich an der
> Genauigkeit des Ergebnisses (3 Nachkommastellen sind gefordert) etwas
> ändert. Richtig?

Nein, siehe Antwort eins drüber.

von Christian W. (christian_w)


Lesenswert?

Aha, langsam kommt Licht in's Dunkel.

Heißt das also, dass ein Präprozessor-Define immer nur 32-Bit-genau ist?

Die Frage ist jetzt nur, wenn ich zwar in einer Funktion Pi berechne, 
dann aber den Wert über den Rückgabetyp long double zurückgebe und 
irgendwo anders verrechne, ist die Genauigkeit dann nicht auch wieder 
den Bach runter?

Christian

von Peter II (Gast)


Lesenswert?

Christian W. schrieb:
> Heißt das also, dass ein Präprozessor-Define immer nur 32-Bit-genau ist?

ein Define ist ein Text nicht mehr und nicht weniger.

von user (Gast)


Lesenswert?

Heißt das also, dass ein Präprozessor-Define immer nur 32-Bit-genau ist?
nein der preprozessor macht nur eine testuelle ersetzung, das heist er 
ersetzt jeden vorkommen von MY_PI durch 3.14159265358979323846. Die 
umwandlung in float/double macht dann der compiler

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Fpga Kuechle schrieb:
> Doch es könnte genauer werden.
> Die Floating point units rechnen intern mit einer höheren Genauigkeit
> als die "integer" Einheit.

Mit Betonung auf könnte

Wenm Compiler für float / double erzeugen kommt es durchaus vor, daß ihm 
die float-Register ausgehen und er float-Werte (temporär) in nicht-FPU 
Registern oder auf dem Stack zwischenlagern muss.

Dann hängt die erreichte Genauigkeit von Faktoren ab wie 
Optimierungsgrad oder vom umgebenden Code, der scheinbar nix mit der 
eigentlichen Berechnung zu tun hat.

von Peter II (Gast)


Lesenswert?

Johann L. schrieb:
> Dann hängt die erreichte Genauigkeit von Faktoren ab wie
> Optimierungsgrad oder vom umgebenden Code, der scheinbar nix mit der
> eigentlichen Berechnung zu tun hat.

das ist sogar eine extra Option vom Compiler. Im Standard sollte es so 
rechnen das das Ergebnis mit double nachvollziehbar ist. (also etwas 
ungenauer als es sein könnte)

http://christian-seiler.de/projekte/fpmath/

von Fpgakuechle K. (Gast)


Angehängte Dateien:

Lesenswert?

Christian W. schrieb:
> Aha, langsam kommt Licht in's Dunkel.
>
> Heißt das also, dass ein Präprozessor-Define immer nur 32-Bit-genau ist?

"immer" ist immer falsch ;-)

Also m.E. kann man die Fragen nach der besten Implementierung nur anhand 
der Hardware klären. Deshalb zwei Schnipsel aus dem Datenblatt zu einem 
der Urväter der Fliesskommaberechnung - der 8087 FPU.

Früher sah die Hardwarearchitektur mal so aus

RAM <-> CPU <-> FPU

Die FPU (80x87)rechnet intern mit 80 bit (Schnipsel 1)
die CPU kann aber nur 64 bit rüberreichen (Schnipsel 2, Op-code)

-> will man also die höchste Genauigkeit muss man Pi auf der FPU 
berechnen und kann es nicht als Konstante rüberreichen. Das gestattet 
der Befehlssatz (Assembler) der CPU nicht. Damit ist es egal ob man nun 
in C, Pascal etc. rechnet - es geht nicht.

Das erklärt erstmal warum in dem von Dir erwähenten C-Code Pi berechnet 
wird.

Schaut man sich die FPU-register genauer an fällt weiterauf, das die 
nicht beliebig zugreiffbar sind, sondern als Stack orientiert sind. Man 
kann also das berechnete PI nicht auf Dauer auf einer fixen Addresse 
speichern.

Das würde erklären warum Pi immer neu berechnet wird.

Bei anderen Controllern wie bspw ARM-Cortex-M4 mit FPU-Option kann das 
wieder anders aussehen. Beim angesprochenen ARM sind FPU-Register wie 
"normale" Register 32 bit breit. Da bringt berechnen statt Konstante 
kein Plus an Genauigkeit - ARM kann an dieser Stelle wohl nicht besser 
als 32bit Fliesskomma.

Interessant finde ich dann wieder späterer intel FPU#s, die bringen 
einen Befehl mit der PI mit der maximalen genauigkeit bereitstellt 
(FLDPI).
Pi ist dabei:

S = 0.f * 2^2
mit:
f = C90FDAA2 2168C234 C


Wie man aber dem C-Compiler sagt, das er dieses Feature im Assemblercode 
nutzt (wenn das Target das unterstützt) ist noch unklar. Aber 
wahrscheinlich nicht in dem man ein define mit möglichst vielen Stellen 
benutzt.

MfG,

*http://www.ece.usu.edu/ece_store/spec/8087.pdf - Datenblatt 8087
*http://home.agh.edu.pl/~amrozek/x87.pdf Datenblatt x87 bei IA32 S.23

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Fpga Kuechle schrieb:
> Wie man aber dem C-Compiler sagt, das er dieses Feature im Assemblercode
> nutzt (wenn das Target das unterstützt) ist noch unklar.

Seit C99 gibt es auch hexadezimale Gleitkommakonstanten.  Der Sinn
ist dabei, dass man auf diese Weise eine Gleitkommazahl mit einem
definierten, 1:1 vergleichbaren Bitmuster festlegen kann.

Für irrationale Zahlen wird aber auch das nicht helfen, sie exakt
abzubilden. ;-)

von Fpgakuechle K. (Gast)


Lesenswert?

Jörg Wunsch schrieb:

> Seit C99 gibt es auch hexadezimale Gleitkommakonstanten.  Der Sinn
> ist dabei, dass man auf diese Weise eine Gleitkommazahl mit einem
> definierten, 1:1 vergleichbaren Bitmuster festlegen kann.
>
> Für irrationale Zahlen wird aber auch das nicht helfen, sie /exakt/
> abzubilden. ;-)

Nicht nur aus diesem Grund scheint mir die Variante Pi über Arkustangens 
zu deklarien von Vorteil. Das wurde oben auch vorgeschlagen und bei 
Recherchen zu Pi und C stößt man auch öfters auf diesen Vorschlag. 
Darüber könnte man auch eine intrinsic function basteln anhand derer der 
Compiler erkennt was er zu assemblieren hat, hier also den Befehl die 
Konstante PI zu laden.

*http://de.wikipedia.org/wiki/Intrinsische_Funktion

MfG,

BTW: Da die FPU bei intel zu SSE mutiert ist, muß man hinsichtlich 
optimalet float-programmierung heutzutage nach SSE suchen?

von Dirk B. (dirkb2)


Lesenswert?

Fpga Kuechle schrieb:
> Wie man aber dem C-Compiler sagt, das er dieses Feature im Assemblercode
> nutzt (wenn das Target das unterstützt) ist noch unklar. Aber
> wahrscheinlich nicht in dem man ein define mit möglichst vielen Stellen
> benutzt.

Warum sollte es nicht?
Das ist doch eine ziemlich einfache Optimierung für den Compiler.

von Walter (Gast)


Lesenswert?

Fpga Kuechle schrieb:
> Nicht nur aus diesem Grund scheint mir die Variante Pi über Arkustangens
> zu deklarien von Vorteil.

und was lässt sich über die Genauigkeit des so errechneten PI sagen?

von Fpgakuechle K. (Gast)


Lesenswert?

Dirk B. schrieb:
> Fpga Kuechle schrieb:
>> Wie man aber dem C-Compiler sagt, das er dieses Feature im Assemblercode
>> nutzt (wenn das Target das unterstützt) ist noch unklar. Aber
>> wahrscheinlich nicht in dem man ein define mit möglichst vielen Stellen
>> benutzt.
>
> Warum sollte es nicht?
> Das ist doch eine ziemlich einfache Optimierung für den Compiler.

Woran soll der Compiler erkennen das man hier Pi wie für die FPU meint 
und nicht eine Näherung für Pi? Oder irgendeinen Skalierungsfaktor der 
nur so aussieht wie PI.


also bspw bei
#define M_PI 3,141526536

den FPUbefehl
und bei
#define M_PI 3,14152653
oder
#define M_PI 3,1415265358
 nicht?


abgesehen von anderen schreibweisen
wie 0,31415926536 * 10;

Exakt wäre eine Konstante wie oben genannt:
S = 0.f * 2^2
mit:
f = C90FDAA2 2168C234 C

Also für den Programmierer ist es sicher nicht einfacher wenn er erst Pi 
auf 20+ Stellen nachschauen und exakt eintippern muß um damit den 
gewünschten assembler-befehl zu erzeugen.

Ob eine einzelne Inline-Assembler Zeile das Problem lösen kann ist auch 
zu bezweifeln, da es sich bei der hier beispielhaft verwandten FPU um 
eine mit Registerstack handelt, wo übliche calling conventions versagen.

MfG,

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Fpga Kuechle schrieb:
> also bspw bei
> #define M_PI 3,141526536

Nur zur Richtigstellung: Du meinst hier den Dezimalpunkt, nicht das 
Komma.

P.S.
Wie wärs mit PI auf 800 Stellen?
1
int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
2
for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
3
f[b]=d%--g,d/=g--,--b;d*=b);}

von Fpgakuechle K. (Gast)


Lesenswert?

Walter schrieb:
> Fpga Kuechle schrieb:
>> Nicht nur aus diesem Grund scheint mir die Variante Pi über Arkustangens
>> zu deklarien von Vorteil.
>
> und was lässt sich über die Genauigkeit des so errechneten PI sagen?

Es soll nicht berechnet werden sondern als Konstante eingesetzt. Also 
der Compiler erkennt das hier eine Konstante deklariert wird, berechnet 
diese und setzt die dann ein.

also die deklaration

const T_floatType_with_best_presision C_PI = 4.0*atan(1.0);

wird nach compilieren durch das Laden des Registers/Stack mit der 
optimalen Konstante ersetzt.

Dort wird das für FORTRAN erklärt:
http://stackoverflow.com/questions/2157920/why-define-pi-4atan1

Wie das bei C genau gemacht wird ist mir unbekannt, es ist ein 
Rklärungsversuch warum sich im Netz immer wieder vorgeschlagen wird Pi 
über den arctan zu deklarieren -> weil das eben eine Möglichkeit ist 
eine Zahl mit unendlich vielen Stellen mit einer endlichen Anzahl von 
Tastaturanschlägen exakt einzutippen. Und auf einer Tastatur ohne 
griechische Buchstaben ;-)

MfG,

von Fpgakuechle K. (Gast)


Lesenswert?

Frank M. schrieb:
> Fpga Kuechle schrieb:
>> also bspw bei
>> #define M_PI 3,141526536
>
> Nur zur Richtigstellung: Du meinst hier den Dezimalpunkt, nicht das
> Komma.

Ja!

>
> P.S.
> Wie wärs mit PI auf 800 Stellen?
>
1
> int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b++]=a/5;
2
> for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a)for(b=c;d+=f[b]*a,
3
> f[b]=d%--g,d/=g--,--b;d*=b);}
4
>

Nimm die atan-Variante, da bekommst du alle Stellen ;-).

MfG,

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Für irrationale Zahlen wird aber auch das nicht helfen, sie /exakt/
> abzubilden. ;-)

Immerhin ist es möglich, mit manchen irrationalen Zahlen exakt zu 
rechnen bzw. rechnen zu lassen:

1) man begnügt sich mit +, -, *, / und Kompositionen davon.
2) und die Zahl(en) sind nicht transzendent wie beispielsweise

von Babbage (Gast)


Lesenswert?

In Indiana wurde mal ein Gesetzesentwurf vorgelegt (und beinahe auch 
beschlossen) dass Pi auf 3,2 festgelegt wird.

http://de.wikipedia.org/wiki/Indiana_Pi_Bill

Vielleicht hat er nicht gewußt dass PI nun doch auch 3.141.. bleibt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Babbage schrieb:
> In Indiana wurde mal ein Gesetzesentwurf vorgelegt (und beinahe auch
> beschlossen) dass Pi auf 3,2 festgelegt wird.

Wenn man auf einem Gebirgspass lebt (wo die Erdoberfläche hyperbolische 
Geometrie hat) ist das Verhältnis von Umfanng zu Durchmesser eines 
Kreises größer als 3.1415....  Wahrscheinlich wuchs der legendäre Mr. 
Goodwin auf einem Pass auf und hat einfach mal nachgemessen anstatt 
theoriegläubig Kreisumfang / Durchmesser = 3.1415... nachzubeten :-)

Das Gesetz kam schlichweg deshalb nicht durch den Senat, weil die Herren 
Senatoren

1) vom Schulsystem indoktrinierte Ignoranten waren, die Euklids 
5. Postulat als gottgegeben ansahen

2) oder in Tälern oder auf Bergen wohnten (wo das Verhältnis von Umfang 
zu Durchmesser eines Kreise aufgrund der dort herrschenden sphärischen 
Geometrie) bekanntlich kleiner als 3.1415... ist;

3) oder in den Plains aufwuchsen wo Umfang zu Durchnesser eines Kreise 
tatsächlich 3.1415... ist.

Oder alles zusammen.

Verfolgt man den Lauf der Geschichte jedoch weiter, so erkennt man, daß 
Mr. Goodwin einfach nur seiner Zeit voraus war:

Noch keine 20 Jahre später revolutionierte ein gewisser Hr. Einstein das 
mathematisch-physikalische Weltbild durch eine Gravitationstheorie in 
Gestalt einer Geometrisierung von Raum und Zeit, nach welcher der Raum 
außerhalb von Himmelskörpern tatsächlich eine hyperbolische Geometrie 
aufweist.

Wer es nicht glaubt: Nachmessen!

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Fpga Kuechle schrieb:
> Früher sah die Hardwarearchitektur mal so aus
>
> RAM <-> CPU <-> FPU
>
> Die FPU (80x87)rechnet intern mit 80 bit (Schnipsel 1)
> die CPU kann aber nur 64 bit rüberreichen (Schnipsel 2, Op-code)

Stimmt nicht. Das Laden eines 80-Bit-Wertes ist das, was in dem von dir 
verlinkten (etwas verwirrenden) Dokument als "Temporary Real Memory to 
ST(0)" bezeichnet wird.

> -> will man also die höchste Genauigkeit muss man Pi auf der FPU
> berechnen und kann es nicht als Konstante rüberreichen. Das gestattet
> der Befehlssatz (Assembler) der CPU nicht.

Doch, tut er. Siehe z.B.
http://www2.deec.uc.pt/~jlobo/tc/opcode_f.html
1
FLD     Floating point load
2
3
    operand       8087         287        387      486     Pentium
4
    reg          17-22        17-22       14        4       1      FX
5
    mem32       (38-56)+EA    38-56       20        3       1      FX
6
    mem64       (40-60)+EA    40-60       25        3       1      FX
7
    mem80       (53-65)+EA    53-65       44        6       3      NP

Oder wenn's von Intel selbst kommen soll:

"The double extended-precision format is normally reserved for holding 
intermediate results in the x87 FPU registers and constants. Its extra 
length is designed to shield final results from the effects of rounding 
and overflow/underflow in intermediate calculations. However, when an 
application requires the maximum range and precision of the x87 FPU (for 
data storage, computations, and results), values can be stored in memory 
in double extended-precision format." (*)

Das 80-Bit-Format wird von gcc auch über den Typ long double 
unterstützt.

(*) http://home.agh.edu.pl/~amrozek/x87.pdf Seite 8-17.

von Dirk B. (dirkb2)


Lesenswert?

Fpga Kuechle schrieb:
> Woran soll der Compiler erkennen das man hier Pi wie für die FPU meint
> und nicht eine Näherung für Pi? Oder irgendeinen Skalierungsfaktor der
> nur so aussieht wie PI.

Darum:
Fpga Kuechle schrieb:
> in dem man ein define mit möglichst  vielen  Stellen  benutzt.

von Fpgakuechle K. (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Fpga Kuechle schrieb:
>> Früher sah die Hardwarearchitektur mal so aus
>>
>> RAM <-> CPU <-> FPU
>>
>> Die FPU (80x87)rechnet intern mit 80 bit (Schnipsel 1)
>> die CPU kann aber nur 64 bit rüberreichen (Schnipsel 2, Op-code)
>
> Stimmt nicht. Das Laden eines 80-Bit-Wertes ist das, was in dem von dir
> verlinkten (etwas verwirrenden) Dokument als "Temporary Real Memory to
> ST(0)" bezeichnet wird.
>
>> -> will man also die höchste Genauigkeit muss man Pi auf der FPU
>> berechnen und kann es nicht als Konstante rüberreichen. Das gestattet
>> der Befehlssatz (Assembler) der CPU nicht.
>
> Doch, tut er. Siehe z.B.
> http://www2.deec.uc.pt/~jlobo/tc/opcode_f.html
>
1
> FLD     Floating point load
2
> 
3
>     operand       8087         287        387      486     Pentium
4
>     reg          17-22        17-22       14        4       1      FX
5
>     mem32       (38-56)+EA    38-56       20        3       1      FX
6
>     mem64       (40-60)+EA    40-60       25        3       1      FX
7
>     mem80       (53-65)+EA    53-65       44        6       3      NP
8
>

Sicher? Also das intel-paper bezieht sich auf 80X87 der IA32 
Architektur,
also 32bit processoren. Der 8087 ist der Co vom 8086 als 16bit. In dem
PNG-Schnipsel des Instructions set wird gezeigt das ganze zwei bit 
benutzt werden um die Operandenbreite zu codieren (Bitfeld M)? und da 
sind keine
80 bit vorgesehen. Und das PNG ist auch von intel. Ich stimme zu, das 
ist verwirrend, ich bin mir da auch nicht 100% sicher, halte aber den 
Auszug des Instructions-code für ein sehr starkes Argumenten gegen die 
These das es bei diesem Co-Prozessor 80 bit Zugriffe auf die FPU gibt.

Und der 8087 ist hier nur beispielhaft gemeint. Das bis jetzt noch nicht
näher beschriebene Code-schnipsel des TO kann auch für eine andere 
machine
gedacht sein (DSP, ibm360, space-ASIC) bei der die interne Darstellung 
höhere Genauigkeit aufweist als mit dem Speicher austauschbar ist.
Vielleicht gibt es eine solche Maschine auch nicht aber der Code würde 
die maximal verfügbare Genauigkeit ausnutzen.

MfG,

von Fpgakuechle K. (Gast)


Lesenswert?

Dirk B. schrieb:
> Fpga Kuechle schrieb:
>> Woran soll der Compiler erkennen das man hier Pi wie für die FPU meint
>> und nicht eine Näherung für Pi? Oder irgendeinen Skalierungsfaktor der
>> nur so aussieht wie PI.
>
> Darum:
> Fpga Kuechle schrieb:
>> in dem man ein define mit möglichst  vielen  Stellen  benutzt.

?Also in der Spec für den compiler soll stehen"

"Wenn Sie möglichst viele Stellen für Pi im define verwenden wird die 
FPU-interne Konstante genutzt, wenn mindestens eine stelle weniger als 
möglichst dann diese." ?

Das ist dann aber scherzhaft gemeint, oder?

Und wenn man bei den beispielwhaft 200 Stellen sich an einer vertippt 
...

Also da muss eine eindeutige Notation verwendet werden. So wie wenn man 
ein Drittel möchte auch "ein Drittel" sagt/notiert oder "1/3" und nicht 
0.33333333333333333... .

Wenn man Pi möchte dann sollte man auch pi verlangen und keine gekürzte 
Variante.

MfG

von Chuck (Gast)


Lesenswert?

>Für irrationale Zahlen wird aber auch das nicht helfen, sie exakt
>abzubilden. ;-)
Chuck Norris kann das. Er kennt alle Stellen von PI!

von Rolf M. (rmagnus)


Lesenswert?

Fpga Kuechle schrieb:
> Sicher?

Ich hab's noch nicht selbst ausprobiert, aber ich hab extra noch eins 
von meinen alten verstaubten x86-Assembler-Büchern aus dem Regal 
gezogen, und da wird das bestätigt. Darin findet sich eine ähnliche 
Tabelle mit Taktzyklen für die Instruktion ab 8087.
Ich kann mich auch noch aus dem Turbo Assembler an die Datentypen BYTE, 
WORD, DWORD, QWORD und TBYTE erinnern. Letzterer war eben der 
80-Bit-Datentyp.

> Also das intel-paper bezieht sich auf 80X87 der IA32 Architektur,
> also 32bit processoren. Der 8087 ist der Co vom 8086 als 16bit. In dem
> PNG-Schnipsel des Instructions set wird gezeigt das ganze zwei bit
> benutzt werden um die Operandenbreite zu codieren (Bitfeld M)? und da
> sind keine 80 bit vorgesehen.

Das gilt aber nur für die Variante "Integer/Real Memory to ST(0)". Die 
80-Bit-Instruktion ist wie schon geschrieben die separate Variante 
"Temporary Real Memory to ST(0)". Die hat auch den gleichen Opcode wie 
der in meinem Buch angegebene 80-Bit-Speicherzugriff.
Ich vermute, daß das "Temporary" hier darauf anspielt, daß die 
Instruktion wie in dem von mir verlinkten Dokument eher dafür gedacht 
ist, um Zwischenergebnisse mit vollen 80 Bit auch in den Speicher 
schreiben zu können.

> Und der 8087 ist hier nur beispielhaft gemeint. Das bis jetzt noch nicht
> näher beschriebene Code-schnipsel des TO kann auch für eine andere
> machine gedacht sein (DSP, ibm360, space-ASIC) bei der die interne
> Darstellung höhere Genauigkeit aufweist als mit dem Speicher austauschbar
> ist.

Ich fand's erstaunlich, jetzt zu lesen, daß man mit Absicht intern mit 
größerer Bitbreite rechnet als man nachher extern üblicherweise 
verwendet, damit Zwischenergebnisse genauer sind. In C will man das 
nicht unbedingt immer, weil das Verhalten dann nicht der Spezifikation 
entspricht. Man spricht in so einem Fall von "excess presicion". Deshalb 
gibt es die oben schon mal von jemandem erwähne Möglichkeit, den 
Compiler zu zwingen, jedes Zwischenergebnis erst in den Speicher zu 
schreiben und wieder von da zu lesen, um die Größe auf diese Weise auf 
32 oder 64 Bit zu reduzieren. Das macht die Sache zwar tierisch lahm, 
aber sorgt dafür, dass das Verhalten dann der Vorgabe von ISO-C 
entspricht.

von Lifeofpi (Gast)


Lesenswert?

Seit dem 14. März 1988 feiern Mathematik-Freunde in aller Welt den Tag 
der Kreiszahl. Aufgrund der amerikanischen Datumsschreibweise 3-14-15 
gerät er in diesem Jahr zum Super-Pi-Tag.


Heise...

von Fpgakuechle K. (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Fpga Kuechle schrieb:
>> Sicher?
>
> Ich hab's noch nicht selbst ausprobiert, aber ich hab extra noch eins
> von meinen alten verstaubten x86-Assembler-Büchern aus dem Regal
> gezogen, und da wird das bestätigt.

OK, da habe ich mich geirrt, "80 bit laden" ist wohl möglich. Ich hab 
mal aus meinen Regal auch mal des vergilbteste Lehrbuch gezogen - 
"Einführung in die 16bit-Mikrorechentechnik mit dem K1860 WM 86" 
Militärverlag 1988. Der K1810WM86 ist ein "Sowjetischer" kompatibler 
Nachbau zum intel 8086, WM87 der zum 8087. Das 80 bit Format heisst dort
"Gleitkomma nicht normalisiert (temporäres Format)" und es gibt 3 
Ladebefehle für float:
FLD GK kurz     11011001
FLD GK lang     11011101
FLD GK temporar 11011011  //den hab ich übersehen

Und es werden auch Konstantenladebefehle erwähnt, aber nicht welche 
Genauigkeit damit realisiert wird:
FLDZ    Null
FLD1    Eins
FLDPI   Pi
FLDL2T  Log2 10

> Ich fand's erstaunlich, jetzt zu lesen, daß man mit Absicht intern mit
> größerer Bitbreite rechnet als man nachher extern üblicherweise
> verwendet, damit Zwischenergebnisse genauer sind.

Das hat mich wiederum nicht überrascht. Meine antrainierte 
Erwartungshaltung bei Hand- und Maschinenrechnung ist das immer die 
gültigen Stellen angegeben werden - sind weniger Stellen gültig gibt man 
(bei Handrechnung) die ungültigen nicht an (Beisp Einkaufspreis, 5.99 € 
und nicht 5.9900000€. Hat man nun eine fixe Stellenanzahl die immer 
ausgegeben werden muß bspw. Mantisse  52 bit dann müssen die oberen 51 
Stellen genau sein, die letzte gerundet. Deshalb genauere 
Zwischenergebnisse.

> In C will man das
> nicht unbedingt immer, weil das Verhalten dann nicht der Spezifikation
> entspricht.

OK, das ist mir Bitzähler neu, ich bin da eher auf der Seite derer die 
eine garantierte Genauigkeit wollen. Dazu gibt es recht interessante 
Abhandlungen von William Kahn - der mathematiker der intel bei floating 
point beraten hat:

http://en.wikipedia.org/wiki/Rounding#The_table-maker.27s_dilemma

MfG,

von (prx) A. K. (prx)


Lesenswert?

Damit kein falscher Eindruck entsteht sei noch daran erinnert, dass die 
Anzahl Bits, mit der auf PCs mit Fliesskommawerten bei Zwischenwerten 
durchschnittlich gerechnet wird, mittlerweile immer geringer wird, also 
die Ergebnisse im Gesamtmittel immer ungenauer werden.

In 16- und 32-Bit Zeiten rechnete man, wie hier ausgiebig beschrieben, 
bei Zwischenwerten meist im 80 Bit Format des 8087 Koprozessors und 
dessen internen Nachfahren.

Seit zunehmend 64-Bit Programme eingesetzt werden entfällt dieses 80-Bit 
Zwischenformat. Denn das 64-Bit Programmiermodell der üblichen 
Betriebssysteme sieht an Stelle des x87 Befehlssatzes SSE vor. Und da 
steht auch für Zwischenwerte nur das 64-Bit Format zur Verfügung.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.