PräzisionGrundlage: Darstellung von Fließkommazahlen auf dem RechnerEine n-stellige Gleitpunktzahl x zur Basis B (meist 2, 8, 10 oder 16) hat die Form: x = +/- ( 0.z_1 z_2 z_3 ... z_n ) * B^(E - E_bias) mit z_i ∈ { 0, 1, .. B-1 } falls x != 0: z_1 != 0 (normalisierte Gleitpunktdarstellung) Der Anteil ( 0.z_1 z_2 z_3 ... z_n ) wird als Mantisse bezeichnet (Beispiel für eine 8-Stellige Mantisse: 0.10001010). Der Exponent E ist eine ganze Zahl. Für diese benutzt man kein Vorzeichen, sondern stellt die negativen Exponenten mit Hilfe eines Bias E_bias dar (E bezeichnet man als physischen Exponenten und (E-E_bias) als logischen Exponenten). B und E_bias werden nicht abgespeichert, sondern werden durch per Konvention festgelegt. Da z_1 in obiger Darstellung bei Basis B = 2 praktisch immer 1 ist, außer für die Null, muss man z_1 nicht (in einem Bit) speichern. Man erhält so die packed mantissa-Darstellung: x = +/- ( 1.z_1 z_2 z_3 ... z_n ) * B^(E - E_bias) Hier kann z_1 auch Null sein. Allerdings kann man jetzt die Null nicht mehr darstellen. Deshalb legt man fest für den Fall, das E = 0 ist, dass die Mantisse nicht um "1." ergänzt wird. Man spricht hier von einer denormalisierten Mantisse (einem "Denorm"). IEEE-754 Standard für double precision-Zahlen, als Basis wird 2 verwendet:
MaschinengenauigkeitDie Maschinengenauigkeit (Präzision) eps ist die kleinste positive Zahl, für die auf dem Computer gilt:1. + eps != 1. Für positive Zahlen ε kleiner als eps gilt somit: (1 + ε) = 1 1 + ε wird also nach der Addition wieder auf 1 gerundet. Bei der Bestimmung von eps auf einem moderenen x86 ist zu beachten, dass im floating point register eine andere Präzision benutzt wird als im Speicher (Für den IEEE-754 Standard siehe z.B.: http://www.etsimo.uniovi.es/~antonio/uned/ieee754/IEEE-754references.html):
Das folgende Programm verdeutlicht diesen Unterschied - Compiler g++ auf einem Linux-x86 beim Kompilierung ohne Optimierung (d.h. -O0):
#include<stdio.h>
#include<limits> // function numeric_limits
int main()
{
double eps_Double_Extended = 1.0;
while( true )
{
if( 1. + eps_Double_Extended == 1. )
break;
eps_Double_Extended *= 0.99;
}
double eps = 1.0;
while( true )
{
double temp = double(1.) + eps ;
if( temp == double(1.) ) break;
eps *= 0.99;
}
// Außerdem kann man die Präzision direkt mit der Funktion
// numeric_limits erhalten:
double epsilon = std::numeric_limits<double>::epsilon();
printf("eps : %.4g \n", eps) ;
printf("eps (double Extended): %.4g \n", eps_Double_Extended) ;
printf("epsilon : %.4g \n", epsilon) ;
return 0;
}
Ausgabe auf meinem PC:
eps : 1.102e-16 eps (double Extended): 5.417e-20 epsilon : 2.22e-16 Berechnung der Stellen in der Mantisse mit Hilfe von epsDie Anzahl der Stellen n der Mantisse erhält man übern = - log_2(eps) - 1 = - ln(eps)/ln(2) - 1 Die -1 ergibt sich aus der packed mantissa-Darstellung. Beispiel (3-stellige duale Rechnung auf der linken Seite des ≈-Zeichens): 1.00000 + 0.00011 = 1.00011 ≈ 1.00 = 1. (abrunden) 1.00000 + 0.00100 = 1.00100 ≈ 1.01 > 1. (aufrunden) Das Runden ergibt sich, da die Addition auf dem Math-Coprozessor (floating point register) mit höherer Prezision ausgeführt wird. Ab Zahlen größergleich 0.001(dual) = 0.125(dezimal) erhält man bei der Addition durch Aufrunden Zahlen größer 1, d.h. eps = 0.125(dezimal) Für n erhält man n = -log_2(0.125) - 1 = 2; d.h. 2-Stellen in packed mantissa-Darstellung Für eps ≈ 1.102e-16 erhält man also 52-Stellen, wie im IEEE-Standard beschieben. Home Klick hier! |
![]() KI-Team Berlin Künstliche Intelligenz Informationstechnologie für das 21.Jahrhundert |