C - Gleitkomma Genauigkeit



  • Hallo,

    ich komme einfach nicht weiter.

    Die Aufgabe ist

    Eine andere Funktion benutzt ein Iterationsverfahren und liefert als double die positive
    Quadratwurzel eines als Parameter zu übergebenden Radikanden mit der höchst möglichen
    Genauigkeit zurück.
    Beachten Sie die Ungenauigkeit reeller Datentypen

    Nochmal meine Funktion

    double quwl ( double rad )
    {
    auto double xN = 1 , xNplus1 = rad ;

    auto unsigned char i ;
    
    for ( i = 1 ; i < 10 ; i ++ )
    {
    	xN = xNplus1 ;
    	xNplus1 = 1 / ( 2 * xN ) * ( xN * xN + rad ) ;
    }
    
    return xNplus1 ;
    

    }

    Ich verstehe einfach nicht was die Aufgabe bzgl. der Genauigkeit will.

    Einerseit habe ich beim Test von double Werten gemerkt, obwohl

    eine Genauigkeit von 15 (signifkaten) Stellen für double angegeben ist.
    Es durchaus Bsp. gibt in denen er mehr als 15 (signifkanten) Stellen unterscheiden kann.

    Andereseits wenn gesagt ist dass der double eine bestimmte höchste Genauigkeit (15 stellen) hat, dann rechnet das Programm doch selbst schon mit seiner höchsten Genauigkeit. Was gibt es da noch zu beachten?

    Also ich sehe zwei Szenarien wenn man bspw.
    1.
    2.2 * 2.0 rechnet dann ist eig das genaueste Ergebnis das man angeben darf

    4.4000 (doppelt so viele Nachkommastellen)

    Wenn man 4.4000000 angeben würde wäre das genauer als man das Ergebnis eig kennt

    Ich denke aber nicht das die Aufgabe so gemeint ist und wüsste auch nicht wie ich das implementieren würde auf anhieb

    1. Wie oben schon gesagt
      ich mache ja Berechnung mit xN in meiner Funktion und weise dann xNplus1
      zu. Ich brauche doch eig nichtmal zu wissen wie die Genauigkeit ist.

    wenn er bspw. xN * xN = 2.345 * 2.345 berechnet aber nicht genug stellen hätte um den genauen Wert weiterzugeben. Dann rundet er doch so gut er es eben selber weiß

    ALso kommt am Ende doch das genaueste Ergebnis raus das man eben bekommen kann?

    Hoffentlich kann jemand diesmal weiterhelfen.

    Vielen Dank.



  • @JamesNguyen
    Untersuche doch mal deine Funktion.

    Baue mal eine kleine Testreihe auf. Du könntest beispielsweise 10 Millionen Zufallszahlen erzeugen und danach die Quadratwurzel mit deiner Funktion und mit sqrt() berechnen und dann miteinander vergleichen. Wie groß ist die größte Differenz?

    Das Problem ist die numerische Stabilität. Gewisse Algorithmen reagieren empfindlich auf kleinere Änderungen, Rundungsfehler können sich hochschaukeln. Beispiel: Inverse eine Vandermonde Matrix, Addition (-> Kahan Summe)



  • (tut mir leid aber als anfänger kommt mir dein kurzer absatz der testreihe wie eine eigene Aufgabe vor...)

    update:

    double quwl ( double rad )
    {
    	if ( rad < 0 ) return - 1 ;
    	
    	auto double xN = 1 ;
    	
    	if ( xN > 1.7e154 && xN < 2.3E-154 && rad < 1.7e308 - xN * xN ) return - 1 ;
    	
    	auto double xNplus1 = 1 / ( 2 * xN ) * ( xN * xN + rad ) ;
    	
    	while ( /*xNplus1 != xN &&*/ fabs ( xNplus1 - xN ) > rad * 1e-14 &&
    			xNplus1 > 2.3E-154 && xNplus1 < 1.7e154 && rad < 1.7e308 - xNplus1 * xNplus1 )
    	{
    		xN = xNplus1 ;
    		
    		xNplus1 = 1 / ( 2 * xN ) * ( xN * xN + rad ) ;
    		
    		printf ( "%.20f\n" , xNplus1) ;
    	}
    	
    	return xNplus1 ;
    }
    

    so sieht die aktuelle version aus ich habe ein paar werte probiert und die werte stimmen eig
    bloß das durchaus mal die hinterste stelle falsch ist



  • Ich hab jetzt mal das gemaht

    for ( d = 0.1 ; d < 1000000 ; d *= 2.1 ) printf ( "%2u. %.18f\n" ,
    									 		k ++ , fabs ( sqrt ( d ) - quwl ( d ) ) ) ;
    

    Ausgabe

    1. 0.000000000000000000
    2. 0.000000000000000056
    3. 0.000000000000000000
    4. 0.000000000000000111
    5. 0.000000000000000000
    6. 0.000000000000000444
    7. 0.000000000000000444
    8. 0.000000000000000000
    9. 0.000000000000000000
    10. 0.000000000000000000
    11. 0.000000000000000000
    12. 0.000000000000000000
    13. 0.000000000000003553
    14. 0.000000000000000000
    15. 0.000000000000007105
    16. 0.000000000000014211
    17. 0.000000000000000000
    18. 0.000000000000028422
    19. 0.000000000000000000
    20. 0.000000000000000000
    21. 0.000000000000113687
    22. 0.000000000000113687

    was kann ich damit anfangen?



  • @JamesNguyen sagte in C - Gleitkomma Genauigkeit:

    Also ich sehe zwei Szenarien wenn man bspw.
    1.
    2.2 * 2.0 rechnet dann ist eig das genaueste Ergebnis das man angeben darf
    4.4000 (doppelt so viele Nachkommastellen)

    Wie kommst du darauf?



  • ich hätte gedacht das ist das normale vorgehen

    wenn man zwei Werte multpliziert dann bekommt man die addierten nachkommstellen

    also

    2.00 * 2.000 = 2.00000

    (das ist bei messungen auch so wenn du theoretisch zwei Messwerte exakt kennst 1.0 +-0 * 2.033 +- 0
    dann ist dein bestwert 2.0330)



  • @JamesNguyen sagte in C - Gleitkomma Genauigkeit:

    du theoretisch zwei Messwerte exakt kennst 1.0 +-0 * 2.033 +- 0

    Das ist aber Computer Praxis und du hast nicht 2.033 sondern 2.03299999237060546875 (bei float)



  • @JamesNguyen sagte in C - Gleitkomma Genauigkeit:

    das ist bei messungen auch so wenn du theoretisch zwei Messwerte exakt kennst 1.0 +-0 * 2.033 +- 0
    dann ist dein bestwert 2.0330)

    Nein, das ist falsch. (bzw. deine Annahme +-0 stimmt bei Messwerten nie, man versteht unter 2.17 auch nicht, dass es 2.17000000000 bedeutet, sondern dass die Ungenauigkeit im Bereich der angegebenen Stellen liegt) Du musst Fehlerfortpflanzung rechnen. Nur weil du z. B. mit einem Wert von exakt 2.000000000000000... multiplizierst, hat dein Ergebnis danach nicht auf einmal so eine große Genauigkeit.


Log in to reply