% Content-encoding: UTF-8 \documentclass[ngerman]{article} \usepackage[utf8]{inputenc} \usepackage{multicol,babel} \usepackage{xspace} \setcounter{secnumdepth}{0} \setcounter{tocdepth}{0} %\newcommand{\code}[1]{\texttt{#1}} %\newcommand{\ret}{\textsf{$<$ret$>$}\xspace} \newcommand{\ret}{$\hookleftarrow$\xspace} \renewcommand{\reftextbefore}{auf der vorherigen Seite} \renewcommand{\reftextfacebefore}{auf der gegenüberliegenden Seite} \renewcommand{\reftextafter}{auf der nächsten Seite} \renewcommand{\reftextfaceafter}{auf der gegenüberliegenden Seite} \renewcommand{\figurename}{Abbildung} \begin{document} \title{Gleitkommazahlen – Floating--Point--Numbers} \ifx\shorttitle\undefined\else \shorttitle{Gleitkommazahlen} \fi \author{Michael Kalus} \begin{document} \maketitle Der Umgang mit Gleitkommazahlen hält eine ganze Reihe unerfreulicher Überraschungen für den Unvorsichtigen bereit (z.$\,$B. ist deren Addition nicht assoziativ) und sogar einige für den Vorsichtigen. Man sollte sie in Programmen nicht benutzen, es sei denn, man weiß, was man tut, oder es kümmert einen nicht, dass man völlig falsche Ergebnisse bekommt. Wer gründlicher lernen möchte, was für Probleme die Gleitkomma--Arithmetik in Rechnern bewirkt, könnte mit dem Papier von David Goldberg [1] anfangen. Hier sind Übungen zusammengestellt, mit denen ihr euch in die ANS--Forth--Syntax des Floating Point hineinfinden könnt. Die Beispiele sind in gforth ausgeführt, das für die Plattformen u.$\,$a.\ Mac OS X, Windows und Linux frei verfügbar ist. \begin{multicols}{2} \section{Der floating point stack} Gforth hat einen separaten Gleitkommastack (floating point stack, FPS). Um anzudeuten, dass die Menge der Gleitkommazahlen eine endliche Teilmenge der rationalen Zahlen ist, werden Gleitkommazahlen auf ihrem Stack gerne mit einem \texttt{r} bezeichnet (siehe Glossar). In der Dokumentation des gforth wird eine vereinheitlichte Stacknotation benutzt, aus der zunächst gar nicht ersichtlich ist, dass ein seperater FPS vorliegt. Doch es ist leicht, eine Notation für getrennte Stacks daraus zu machen. Setze dafür die Gleitkommazahlen einfach daneben. Z.$\,$B.: \texttt{( n r1 u r2 -- r3 )} wird zu \texttt{( n u -- ) ( F: r1 r2 -- r3 )} Inspizieren lässt sich dieser Stack mit \texttt{f.s} ganz so, wie wir es schon vom Datenstack her gewohnt sind, der ja mit \texttt{.s} dargestellt werden kann. \section{Übungen} \subsection{Eingabe einer Gleitkommazahl} Als Erstes geben wir eine Zahl mit Dezimalpunkt ein und versuchen, sie als Gleitkommazahl wieder auszugeben. ( \ret bedeutet, dass die Eingabetaste gedrückt worden ist. Dahinter oder darunter folgt die Ausgabe.) \texttt{1234.56789 f.} \ret\\ \texttt{*the terminal*:22: Floating-point stack\\\hspace*{\fill} underflow} Hm, das gibt schon mal eine Fehlermeldung! Warum? Gforth interpretiert Zahlen mit Punkt zwar als doppelt--genaue Zahl, aber diese wird auf den Datenstack gelegt, der FPS bleibt leer, \texttt{f.} greift also ins Leere: \texttt{Stack underflow}. Inspizieren wir die Stacks: \texttt{1234.56789} \ret\\ \texttt{.s} \ret\\ \verb|<2> 123456789 0| \texttt{f.s} \ret\\ \verb|<0>| Um den Interpreter zu veranlassen, unsere Eingabe als Gleitkommazahl zu sehen, muss unsere Eingabe einer bestimmten Form genügen. Erst eine Zeichenkette der Form: \verb|{+ -}{.}|\\ \hspace*{\fill}\verb|{e E}{+ -}| wird als Gleitkommazahl behandelt, die dann auch auf dem FPS landet. Die folgenden Formate führen zu gleichwertigen Eingaben: \texttt{1e 1e0 1.e 1.e0 +1e+0} \ret\\ \texttt{f.s} \ret\\ \verb|<5> 1. 1. 1. 1. 1.| Auch eine Zahl mit negativem Exponenten ist so möglich: \texttt{+12.E-4} \ret\\ \texttt{f.s} \ret\\ \verb|<1> 0.0012| Wir müssen die Gleitkommazahl also mit einem Exponenten schreiben. Neben der Zifferneingabe über die Tastatur (input stream) hält Gforth auch die Möglichkeit bereit, eine Zeichenkette (string) in eine Gleitkommazahl umzuwandeln. \verb|s" 1234.56789" >float ( -- f ) (FPS: -- r )| Hierbei wird dann eine Gleitkommazahl auf den FPS gelegt, wenn die Konversion der Zeichenkette erfolgreich war, und ein \texttt{true} erscheint auf dem Datenstack. \verb|s" 1234xyz56789" >float| hingegen würde ein \texttt{false}--Flag ergeben und der FPS bliebe leer. \subsection{Ausgabe einer Gleitkommazahl} Das Wort \texttt{f.} nimmt eine Gleitkommazahl vom FPS und gibt sie aus. Das ist die einfachste Art: \texttt{f.s} \ret \verb|<1> 0.0012|\\ \texttt{f.} \ret \verb|0.0012| \begin{figure*}[t] \begin{center} \begin{minipage}{0.8\textwidth} \verb|sp@ depth 1- cells dump| \ret\\ \begin{verbatim} 140DFDC: 00 00 00 99 00 00 00 88 - 00 00 00 77 00 00 00 66 ...........w...f 140DFEC: 00 00 00 55 00 00 00 44 - 00 00 00 33 00 00 00 22 ...U...D...3..." 140DFFC: 00 00 00 11 - .... ok \end{verbatim} \end{minipage} \end{center} \caption{\label{dump1}Dump des Datenstacks \texttt{11 22 33 44 55 66 77 88 99}} \end{figure*} Nun probieren wir Gleitkommazahlen auch anders formatiert auszugeben. \texttt{12345.6789e0 fdup cr fe. cr fs.} \ret\\ \verb|12.3456789000000E3|\\ \verb|1.23456789000000E4| Wir sehen, dass \texttt{fe.} die technische (engineering) Notation ergibt. Bei der technischen Notation wird der Exponent immer auf das größtmögliche Vielfache von drei justiert. Dei der wissenschaftlichen (scientific) Notation hingegen wird immer auf eine Stelle vor dem Komma justiert. \subsection{Doppelt--genaue Zahl in eine Gleitkommazahl umwandeln.} Doch wie können nun Zahlen vom Datenstack als Gleitkommazahlen ausgegeben werden? Nun, man schiebt sie einfach mit \verb|d>f| rüber auf den FPS, und gibt sie von dort aus --- jedenfalls im Prinzip. Nun kann \verb|d>f| aber nicht wissen, wie diese Zahl ursprünglich mal auf den Datenstack gekommen ist und welcher Teil davon die Vorkomma-- und welcher die Nachkommastellen repräsentiert. Denn Zahlen auf dem Datenstack sind formlos in Forth, sie können ja alles bedeuten, eine Adresse ebenso wie eine ganze Zahl (integer) oder irgendein Token. Beobachten wir also einmal, was dabei abläuft: \begin{verbatim} : tt ( d -- ) cr .s f.s d>f cr .s f.s cr DPL @ . ; \end{verbatim} Wir erhalten:\\ \texttt{1234.56789 tt} \ret\\ \verb|<2> 123456789 0 <0>|\\ \verb|<0> <1> 123456789.|\\ \verb|5 ok| Nach der Eingabe von \verb|1234.56789| lagen also {\bf zwei} Werte auf dem Datenstack und zunächst nichts auf dem FPS. Mit \verb|d>f| wird die doppelt--genaue Zahl genommen und auf den FPS verschoben. Anschließend ist der Datenstack leer, und der FPS enthält {\bf einen} Wert, eine Gleitkommazahl, mit derselben Ziffernfolge wie die doppelt--genaue Zahl zuvor. Und wo ist der Dezimalpunkt geblieben? Dafür schauen wir in der Uservariablen \texttt{DPL} nach. \texttt{DPL @ .} ergibt \texttt{5}. Das bedeutet, es gab bei der letzten Zahlenkonversion 5 Nachkommastellen. Die Position des Dezimalpunktes wird also aufgehoben, aber nicht automatisch gewertet. Das obliegt dem Programmierer selbst. So weit, so gut. Nur, wie kriegt man die Nachkommastellen wieder in die Gleitkommazahl hinein? Multiplizieren mit \texttt{10e-5} würde die richtige Gleitkommazahl \texttt{1234.56789} zurückliefern. Die \texttt{5} in \texttt{DPL} ist somit der Logarithmus zur Basis $b=10$ unserer gesuchten Zahl $a$ ($x=log_ba$) und man schreibt: \verb|1234.56789 d>f DPL @ s>d d>f fnegate|\\ \verb|falog f* f.| \ret\\ \verb|1234.56789 ok| \subsection{Interne Repräsentation der Gleitkommazahl} In Forth ist es recht einfach, sich anzusehen, wie eine Gleitkommazahl tatsächlich im RAM abgelegt wird. Man kann die Stacks mittels \texttt{DUMP} inspizieren. Da die Stacks in gforth in Richtung kleinerer Adressen wachsen, zeigen die folgenden Sequenzen deren Inhalt: \begin{verbatim} sp@ depth 1- cells dump fp@ fdepth floats dump \end{verbatim} (Das kann in Zukunft allerdings durch Stack--Caching unerwartete Resultate liefern.) Eine Eingabe von: \texttt{hex 11 22 33 44 55 66 77 88 99} \ret\\ \texttt{ok} zeigt uns auf dem Datenstack dann \texttt{.s} \ret\\ \verb|<9> 11 22 33 44 55 66 77 88 99 ok| \begin{figure*}[t] \begin{center} \begin{minipage}{0.8\textwidth} \begin{verbatim} fp@ fdepth floats dump 1412FB8: 40 22 00 00 00 00 00 00 - 40 20 00 00 00 00 00 00 @"......@ ...... 1412FC8: 40 1C 00 00 00 00 00 00 - 40 18 00 00 00 00 00 00 @.......@....... 1412FD8: 40 14 00 00 00 00 00 00 - 40 10 00 00 00 00 00 00 @.......@....... 1412FE8: 40 08 00 00 00 00 00 00 - 40 00 00 00 00 00 00 00 @.......@....... 1412FF8: 3F F0 00 00 00 00 00 00 - ?....... ok \end{verbatim} \end{minipage} \end{center} \caption{\label{dump2}Darstellung der Gleitkommazahlen im Floating--Point--Stack} \end{figure*} Und im \texttt{dump} des Datenstacks dann die Speicherbelegung aus Abbildung \vref{dump1}. Hier wird sichtbar, dass jeweils vier Bytes zur Repräsentation der Zahl benutzt werden. Gforth stellt also einfach--genaue Zahlen in 32bit dar\footnote{Auskunft darüber erhält man so: \texttt{cell .} \ret \texttt{4 ok.} Oder: \texttt{1 cells .} \ret \texttt{4 ok}}. Und die Werte sind absteigend angelegt. Versuchen wir so etwas nun mit Gleikommazahlen. \texttt{decimal} \ret\\ \texttt{ok}\\ \texttt{1.e 2.e 3.e 4.e 5.e 6.e 7.e 8.e 9.e} \ret\\ \texttt{ok}\\ \texttt{f.s} \ret\\ \verb|<9> 1. 2. 3. 4. 5. 6. 7. 8. 9. ok|\\ In Abbildung \vref{dump2} ist nun ersichtlich, dass je Gleitkommazahl immer 8 Bytes, also 64 Bit, benutzt werden. \texttt{float .} \ret \texttt{8 ok}\\ \texttt{1 dfloats .} \ret \texttt{8 ok} Doch dabei ist nun ganz und gar nicht mehr sichtbar, wie die Gleitkommazahl in diesen 64 Bit untergebracht worden ist. Offensichtlich wird da etwas Codiertes hinterlegt [2]. Doch auch dabei ist es mit Forth recht einfach möglich, diese IEEE--754--Codierung nachzuvollziehen. Schauen wir uns das Format einmal bitweise an. Dazu legen wir eine Zahl auf den FPS und dumpen den Stack. \texttt{decimal} \ret \texttt{ok}\\ \texttt{-118.625e0} \ret \texttt{ok}\\ \texttt{f.s} \ret \verb|<1> -118.625 ok|\\ \texttt{fp@ fdepth floats dump} \ret\\ \verb| 1412FF8: C0 5D A8 00 00 00 00 00 - .]......| Binär gelesen ist das: \verb|2 base !| \ret\\ \verb|$C0 .| \ret \verb|11000000 ok|\\ \verb|$5C .| \ret \verb|01011100 ok|\\ \verb|$A8 .| \ret \verb|10101000 ok|\\ ... Dort liegt also die Bitfolge: % $ to fix syntax hilighting \verb|11000000 01011100 10101000 00000000|\\ \verb|00000000 00000000 00000000 00000000| Zum Vergleich diene folgende Sequenz: \verb|2 base ! &118.625 drop .| \ret\\ \verb|11100111101100001 ok| Offensichtlich ist das {\bf nicht} das Gleiche. Im IEEE--754--Gleitkomma--Format gibt es drei Felder, für jede Eigenschaft der Zahl eines: Vorzeichen (sign), Exponent (exp) und dann die Ziffernfolge des binären Bruchteils hinter dem normierten binären Ausdruck (Fraction). Im obigen Beispiel also folgende 64 Bit: sign, 1 Bit = \texttt{1} = negative Zahl\\ Exponent, 11 Bit = \texttt{100 0000 0101}\\ Fraction, 52 bit = \hfill\texttt{1100 1010 1000 0000 0000 0000}\\ \hspace*{\fill}\texttt{0000 0000 0000 0000 0000 0000 0000} \subsection{Normalisierte Darstellung, biased} Dazu wird die Zahl binär umgewandelt, nun ohne Vorzeichen, also ohne die Zweierkomplement--Schreibweise zu nehmen. Wir erhalten: \verb|&118 .| \ret\\ \verb|1110110 ok| Den Wert hinter dem Komma erhalten wir so: \begin{footnotesize} $0.625\ \times\ 2 = 1.25$ wovon die Eins hinter das Komma kommt.\\ $0.25\ \times\ 2 = 0.50$ wovon die Null hinter das Komma kommt.\\ $ 0.5\ \times\ 2 = 1.00$ wovon wieder die Eins hinter das Komma kommt. \end{footnotesize} Außerdem sind wir fertig, weil es nichts weiter umzuwandeln gibt. Unsere Zahl lautet nun: \texttt{1110110.101} Als Nächstes wird der Punkt bis auf die erste Stelle nach links verschoben: \texttt{1110110.101 = 1.110110101 $\times$ 26}. Dieses ist nun die normalisierte Form der Gleitkommazahl. Die erste binäre Eins wird einfach fallen gelassen, da sie immer gegeben ist. Die Fraction (Bruch) steht nun rechts des Punktes und wird solange mit Nullen aufgefüllt, bis alle Bits der Darstellung aufgefüllt sind. Der Exponent ist $6$, aber auch er muss noch binaär geschrieben und mit einem Bias verrechnet werden, damit der kleinstmögliche Exponent die $0$ ist. Im 64--Bit IEEE--754--Format ist der Bias $1023$, der Exponent wird daher als $1023 + 6 = 1029$ aufgeschrieben. Binär also: \verb|%10000000101|. \subsection{Knobelei} \begin{itemize} \item Was sind die kleinsten und größten Zahlen, die auf diese Weise dargestellt werden können? (Also welche Zahlen liegen am nächsten an der Null, welche am weitesten entfernt?) \item Funktoniert die Umwandlung auch mit anderer Basis als 10? \end{itemize} \begin{verbatim} decimal 2 base ! 101010.10 .s <10> 10101010 0 decimal DPL @ .s <3> 170 0 2 ok \end{verbatim} \texttt{DPL} enthält auch hier die 2 Nachkommastellen. Man sieht, dass \texttt{DPL} lediglich angibt, wieviele Zeichen im Eingabestring hinter dem Punkt noch folgten. Es ist also kein \emph{Dezimalpunkt}, sondern einfach nur ein Marker, der noch weiterer Interpretation bedarf. \end{multicols} \newpage \section{Glossar} (Die Regeln, die der Textinterpreter benutzt, um Gleitkommazahlen zu erkennen, stehen im Abschnitt 5.13.2 [Number Conversion], Seite 97 des Handbuches.) \subsection*{Floating--Point--Ausgabe} \begin{tabular}{lll} \texttt{f.} & \texttt{r –} & float-ext “f-dot”\\ & \multicolumn{2}{p{15cm}}{Stelle (die Gleitkommazahl) r ohne Exponent dar, gefolgt von einem Leerzeichen.}\\[\medskipamount] \texttt{fe.} & \texttt{r –} & float-ext “f-e-dot”\\ &\multicolumn{2}{p{15cm}}{Stelle r in der technischen Notation dar (mit dem Exponenten als ein Vielfaches von drei), gefolgt von einem Leerzeichen.} \\ \texttt{fs.} & \texttt{r –} & float-ext “f-s-dot”\\ &\multicolumn{2}{p{15cm}}{Stelle r in der wissenschaftlichen Notation dar (mit dem Exponenten), gefolgt von einem Leerzeichen.} \\ \texttt{f.rdp} & \texttt{rf +nr +nd +np –} & gforth “f.rdp”\\ &\multicolumn{2}{p{15cm}}{Die Ausgabe der Gleitkommazahl \texttt{rf} wird formatiert. Die ganze Breite der Ausgabe beträgt \texttt{+nr} Zeichen. Das Komma ist fixiert, die Anzahl der Stellen hinter dem Komma beträgt \texttt{+nd} und das Minimum an signifikanten Stellen ist \texttt{+np}. \texttt{Set-precision} hat keinen Effekt auf \texttt{f.rdp}.} \end{tabular} Solch eine Notation mit fester Kommastelle wird benutzt, wenn die Anzahl der signifikanten Stellen vor dem Komma mindestens np beträgt und wenn die Stellen vor dem Komma hineinpassen. Dabei wird auf die exponentielle Ausgabe umgeschaltet, wenn die Stellen nicht hineinpassen, oder es werden Sterne ausgegeben, wenn auch das nicht passt. Wir empfehlen ein $nr \ge +5$, um zu vermeiden, dass eine Zahl überhaupt nicht passt. Und wir empfehlen ein $nr \ge pn+5$, um zu vermeiden, dass auf die exponentielle Schreibweise umgeschaltet wird, weil der Gleitkommazahl zu wenig signifikante Stellen bereitgestellt wurden, bietet doch die exponentielle Schreibweise weniger signifikante Stellen. Und wir empfehlen $nr \ge nd+2$, falls Sie Gleitkommazahlen für mehrere Zahlen brauchen. Schließlich sollte $np > nr$, falls die Ausgabe nur in exponentieller Schreibweise erfolgen soll. Hier ist zu sehen, wie die Zahl $1234.5678e23$ von den verschiedenen Formaten ausgegeben wird:\\ \texttt{f. 123456779999999000000000000.}\\ \texttt{fe. 123.456779999999E24}\\ \texttt{fs. 1.23456779999999E26} \subsection*{Austausch zwischen Datenstack und Floating--Point--Stack} \begin{tabular}{lll} \verb|d>f| & d – r & float “d-to-f” \\ \verb|f>d| & r – d & float “f-to-d” \end{tabular} \subsection*{Data und Code ansehen} Die folgenden Worte inspizieren den Stack non-destruktiv: \begin{tabular}{lllp{15cm}} \texttt{.s} & – & tools “dot-s” &{Datenstack ansehen.}\\ \texttt{f.s} & – & gforth “f-dot-s” & {Gleitkommastack ansehen.}\\ \texttt{depth} & – +n & core “depth” & {Tiefe des Datenstacks.}\\ \texttt{fdepth} & – +n & float “f-depth” &{Tiefe des FPS.}\\ \texttt{clearstack} & ... – & gforth “clear-stack” &{Löscht den Datenstack.} \end{tabular} \subsection*{Inspizieren von Speicherbereichen} \begin{tabular}{lll} \verb|?|& a-addr – &tools “question” \\ \verb|dump|& addr u – &tools “dump” \\ \verb|see|& "name" – & tools “see” \\ \verb|xt-see xt|& – & gforth “xt-see” \\ \verb|simple-see "name"|& – & gforth “simple-see” \\ \verb|simple-see-range|& addr1 addr2 – & gforth “simple-see-range” \\ \end{tabular} \subsection*{Floating--Point--Stack--Operatoren} \begin{tabular}{lll} \verb|floating-stack|& – n & environment “floating-stack” \\ &\multicolumn{2}{p{15cm}}{n ist nicht-null, was bedeutet, dass Gforth einen separaten Floating--Point--Stack der Tiefe n hat.}\\[\medskipamount] \verb|fdrop|& r – & float “f-drop” \\ \verb|fnip|& r1 r2 – r2 &gforth “f-nip” \\ \verb|fdup|& r – r r &float “f-dupe” \\ \verb|fover|& r1 r2 – r1 r2 r1 & float “f-over” \\ \verb|ftuck|& r1 r2 – r2 r1 r2 & gforth “f-tuck” \\ \verb|fswap|& r1 r2 – r2 r1 &float “f-swap” \\ \verb|fpick|& u – r &gforth “fpick” \\ &\multicolumn{2}{p{15cm}}{Eigentlich ist der Stackeffekt so: r0 \ldots\ ru u -- r0 ... ru r0} \\[\medskipamount] \verb|frot|& r1 r2 r3 – r2 r3 r1 & float “f-rote” \\ \end{tabular} \subsection*{Floating--Point--Operatoren} \begin{tabular}{lll} \verb|f+|& r1 r2 – r3 &float “f-plus” \\ \verb|f-|& r1 r2 – r3 &float “f-minus” \\ \verb|f*|& r1 r2 – r3 &float “f-star” \\ \verb|f/|& r1 r2 – r3 &float “f-slash” \\ \verb|fnegate|& r1 – r2 & float “f-negate” \\ \verb|fabs|& r1 – r2 &float-ext “f-abs” \\ \verb|fmax|& r1 r2 – r3 &float “f-max” \\ \verb|fmin|& r1 r2 – r3 &float “f-min” \\ \verb|floor|& r1 – r2 &float “floor” \\ &\multicolumn{2}{p{15cm}}{Runde auf den nächsten kleineren Integer-Wert ab, d.h. runde gegen negativ Unendlich.}\\[\medskipamount] \verb|fround|& r1 – r2 &gforth “f-round” \\ &\multicolumn{2}{p{15cm}}{Runde auf den nächsten Integer-Wert. }\\[\medskipamount] \verb|f**|& r1 r2 – r3 &float-ext “f-star-star” \\ &\multicolumn{2}{p{15cm}}{r3 ist r1 hoch r2 }\\[\medskipamount] \verb|fsqrt|& r1 – r2 &float-ext “f-square-root” \\ \verb|fexp|& r1 – r2 &float-ext “f-e-x-p” \\ \verb|fexpm1|& r1 – r2 &float-ext “f-e-x-p-m-one” \\ &\multicolumn{2}{p{15cm}}{r2 = e**r1 -1 }\\[\medskipamount] \verb|fln|& r1 – r2 &float-ext “f-l-n” \\ \verb|flnp1|& r1 – r2 &float-ext “f-l-n-p-one”\\ &\multicolumn{2}{p{15cm}}{r2 =ln(r1 +1) }\\[\medskipamount] \verb|flog|& r1 – r2 &float-ext “f-log” \\ &\multicolumn{2}{p{15cm}}{Der dezimale Logarithmus. }\\[\medskipamount] \verb|falog|& r1 – r2 &float-ext “f-a-log” \\ &\multicolumn{2}{p{15cm}}{r2 = 10**r1 }\\[\medskipamount] \verb|f2*|& r1 – r2 &gforth “f2*” \\ &\multicolumn{2}{p{15cm}}{Multipliziere r1 mit 2.0e0 }\\[\medskipamount] \verb|f2/|& r1 – r2 &gforth “f2/” \\ &\multicolumn{2}{p{15cm}}{Multipliziere r1 mit 0.5e0 }\\[\medskipamount] \verb|1/f|& r1 – r2 &gforth “1/f ” \\ &\multicolumn{2}{p{15cm}}{Teile 1.0e0 durch r1. }\\[\medskipamount] \verb|precision|& – u &float-ext “precision”\\ &\multicolumn{2}{p{15cm}}{u ist die Anzahl der signifikanten Ziffern, die nun von \texttt{F. FE.} und \texttt{FS.} benutzt werden.}\\[\medskipamount] \verb|set-precision|& u – & float-ext “set-precision” \\ &\multicolumn{2}{p{15cm}}{Setzt die Anzahl der signifikanten Ziffern, die nun von \texttt{F. FE.} und \texttt{FS.} benutzt werden, zu \texttt{u.}}\\[\medskipamount] \end{tabular} \subsection*{Winkelfunktionen als Floating--Point--Operationen} Die Winkel werden immer in Radianten angegeben. Ein voller Kreis hat $2\pi$ Radianten. \begin{tabular}{lll} \verb|fsin|& r1 – r2 &float-ext “f-sine” \\ \verb|fcos|& r1 – r2 &float-ext “f-cos” \\ \verb|fsincos|& r1 – r2 r3 &float-ext “f-sine-cos”\\ &\multicolumn{2}{p{15cm}}{r2 =sin(r1 ), r3 =cos(r1 ) }\\[\medskipamount] \verb|ftan|& r1 – r2 &float-ext “f-tan” \\ \verb|fasin|& r1 – r2 &float-ext “f-a-sine”\\ \verb|facos|& r1 – r2 &float-ext “f-a-cos” \\ \verb|fatan|& r1 – r2 &float-ext “f-a-tan” \\ \verb|fatan2|& r1 r2 – r3 &float-ext “f-a-tan-two” \\ &\multicolumn{2}{p{15cm}}{r1/r2 =tan(r3 ). ANS--Forth fordert es zwar nicht, wollte es aber vermutlich, so dass dies die Umkehrung des fsincos ist. In gforth ist es so. }\\[\medskipamount] \verb|fsinh|& r1 – r2 &float-ext “f-cinch” \\ \verb|fcosh|& r1 – r2 &float-ext “f-cosh” \\ \verb|ftanh|& r1 – r2 &float-ext “f-tan-h” \\ \verb|fasinh|& r1 – r2 &float-ext “f-a-cinch” \\ \verb|facosh|& r1 – r2 &float-ext “f-a-cosh” \\ \verb|fatanh|& r1 – r2 &float-ext “f-a-tan-h” \\ \verb|pi|& – r &gforth “pi” \\ &\multicolumn{2}{p{15cm}}{Die Konstante r ist der Wert Pi; das Verhältnis des Kreisumfangs zum Durchmesser.}\\[\medskipamount] \end{tabular} Ein spezielles Problem der Floating--Point--Arithmetik ist, dass ein Test auf Gleichheit oft gerade dann fehlschlägt, wenn man eigentlich erwartet, dass die Werte gleich sein sollten. Daher versucht man, sich mit einer ungefähren Gleichheit zu behelfen (aber man sollte dabei wissen, was man tut). Beachte auch, dass die IEEE NaNs vielleicht anders vergleicht, als du erwartet hattest. Folgende vergleichenden Worte gibt es: \begin{tabular}{lll} \verb|f~rel|& r1 r2 r3 – flag & gforth “f~rel” \\ &\multicolumn{2}{p{15cm}}{ Ungefähre Gleichheit mit relativem Fehler: $|r1-r2|0$ nimm \texttt{f~abs} ; für $r3=0$ nimm bitweisen Vergleich; für $r3<0$ nimm \texttt{fnegate f~rel} . }\\[\medskipamount] \verb|f=|& r1 r2 – f &gforth “f-equals” \\ \verb|f<>|& r1 r2 – f &gforth “f-not-equals” \\ \verb|f<|& r1 r2 – f &float “f-less-than” \\ \verb|f<=|& r1 r2 – f &gforth “f-less-or-equal”\\ \verb|f>|& r1 r2 – f &gforth “f-greater-than” \\ \verb|f>=|& r1 r2 – f & gforth “f-greater-or-equal”\\ \verb|f0<|& r – f & float “f-zero-less-than” \\ \verb|f0<=|& r – f & gforth “f-zero-less-or-equal”\\ \verb|f0<>|& r – f & gforth “f-zero-not-equals” \\ \verb|f0=|& r – f & float “f-zero-equals” \\ \verb|f0>|& r – f & gforth “f-zero-greater-than” \\ \verb|f0>=|& r – f & gforth “f-zero-greater-or-equal”\\ \end{tabular} \section{Literatur} \begin{tabular}{ll} [1] &David Goldberg, "What Every Computer Scientist Should Know About Floating-Point Arithmetic"\\ & ACM Computing Surveys 23(1):5--48, March 1991. \url{http://www.validgh.com/goldberg/paper.ps}\\ {}[2] &\url{http://en.wikipedia.org/wiki/IEEE-754} \end{tabular} \end{document}