Guten Abend,
heute hat mich die Werbebroschüre für ein Werkzeug zur statischen
Codeanalyse erreicht. Dabei wurde angespriesen, daß beispielsweise die
folgende problematische Codestelle gefunden würde:
1
voidfoo(int*depth)
2
{
3
floatadvance;
4
*depth=*depth+1;
5
advance=1.0/(float)(*depth);
6
if(*depth<50)
7
foo(depth);
8
}
9
10
voidbug_in_recursive()
11
{
12
intx;
13
if(random_int())
14
{
15
x=-4;
16
foo(&x);
17
}
18
else
19
{
20
x=10;
21
foo(&x);
22
}
23
}
(ich gehe mal davon aus, daß der Codeschnipsel zu kurz ist, um
Umheberrechte zu haben).
Hier wird die unter Umständen entstehende Division float durch float 0
als Fehler gefunden.
Bislang war ich davon ausgegangen, daß float nach IEEE 754 definiert
ist, wo eine Division durch Null -Inf oder Inf liefert - also mitnichten
eine problematische Operation ist, sondern ganz solide eine Meldung
liefert, (wobei man das ja üblicherweise als Indiz nutzt, daß etwas
numerisch aus dem Ruder läuft).
Deswegen die Frage an die GCC-Fraktion (GCC, ARM-GCC, AVR-GCC): Ist die
Division durch float Null problematisch? Undefiniert? Ist ein float hier
gar nicht nach IEEE 754 definiert?
Irgendwie finde ich, wenn ich nach diesem Thema suche nur Bugreports.
Viele Grüße
W.T.
Walter Tarpan schrieb:> Ist die> Division durch float Null problematisch? Undefiniert? Ist ein float hier> gar nicht nach IEEE 754 definiert?
Undefiniert. Am PC gibts eventuell SIGFPE, am ARM eventuell eine
Floating Point Exception... Wie auch immer, es kommt sicherlich nichts
"sinnvolles" raus, und der Programmierer wollte sicherlich nicht durch 0
teilen - das Programm macht also irgendwas "komisches" - und das ist
noch viel schlimmer als ein Absturz, weil man es nicht bemerkt! - und
das programm dann eine Maschine falsch steuert oder was auch immer.
Mag ja sein, dass das Ganze ein philosophisches Problem ist, aber in dem
Fall, in dem eine Division durch Irgendwas vorkommt, so MUSS auch eine
Division durch Null möglich sein.
Natürlich ist in diesem Falle eine Sonderbehandlung nötig, aber nicht
immer lässt sich ein Problem mit: if (Divisor < 0.01) Spielverderber;
lösen.
Gerade wenn's mal wieder rund (Kreis) geht, kann das Ergebnis auch
sinnvoll sein.
Amateur schrieb:> Mag ja sein, dass das Ganze ein philosophisches Problem ist,
Das Ganze ist kein philosophisches Problem. Es gibt nach IEEE 754 eine
definierte Behandlung der Division durch 0.0FL, bei der -Inf oder Inf
herauskommt, je nach dem welches Vorzeichen der Zähler und die Null
haben.
Die "BLAS" und die "LAPACK"-Libraries haben das auch genau so
implementiert. Mit anderen Numerik-Libraries habe ich noch nie
gearbeitet.
Aber offensichtlich scheint dieses Verhalten eine Eigenschaft dieser
Libraries und nicht des "float"- oder "double"-Datentyps, also nicht
selbstverständlich zu sein.
Amateur schrieb:> Mag ja sein, dass das Ganze ein philosophisches Problem ist
Nö.
Eine Division durch 0 ist ein ganz handfestes Problem.
Sie bedeutet, dass du in der Herleitung deiner Mathe irgendetwas
übersehen hast.
> , aber in dem> Fall, in dem eine Division durch Irgendwas vorkommt, so MUSS auch eine> Division durch Null möglich sein.
Müssen tut nur das, was im C-Standard steht.
Und da steht nichts davon, dass eine Division durch 0 zulässig ist.
> Natürlich ist in diesem Falle eine Sonderbehandlung nötig, aber nicht> immer lässt sich ein Problem mit: if (Divisor < 0.01) Spielverderber;> lösen.
Doch. Das lässt sich immer so lösen.
Wenn du durch 0 dividierst, dann hast du ein Problem. Punkt.
> Gerade wenn's mal wieder rund (Kreis) geht, kann das Ergebnis auch> sinnvoll sein.
Wie soll da irgendwas sinnvoll sein? Was dividierst du 'an einem Kreis',
so dass eine Division durch 0 eine sinnvolle Operation ist? Wenn du je
in der Geometrie auf eine derartige Situation stösst, dann machst du
etwas ganz grundsätzlich falsch, bzw. hast etwas ganz grauslich
übersehen. Und nein, auch ein Tangens von 90° rettet dich da jetzt
nicht.
Karl Heinz schrieb:> Wenn du je> in der Geometrie auf eine derartige Situation stösst, dann machst du> etwas ganz grundsätzlich falsch, bzw. hast etwas ganz grauslich> übersehen.
Daß ich mal einer Aussage von Dir im Bereich der Programmierung vehement
widersprechen würde, hätte ich nie gedacht. Aber in diesem Fall scheint
Dir der Nutzen vermutlich einfach noch nie begegnet zu sein.
Wenn man mit großen Gleichungssystemen (Matrizes) hantiert, ist leider
manchmal das Phänomen eines schleichenden Rangabfalls zu beobachten,
d.h. im Rahmen der Operationen werden die Zeilen der Matrix linear immer
abhängiger. (Wir reden hier nicht über Computergrafik- da kann man
Matrizes meist orthogonalisieren oder sogar orthonormalisieren.) Das ist
insbesondere bei sehr steifen Systemen (d.h. Systeme, bei denen die
Eigenwerte sehr unterschiedliche Größenordnungen haben) der Fall.
Hier ist es sinnvoll, die Operationen einfach zuzulassen - Ergebnis sind
dann Vektoren oder Matrizes, bei denen einige Stellen mit Inf oder NaN
markiert sind - und den aufgetretenen Problemen auf einer höheren Ebene
zu begegnen. Oft sind auch -selbst wenn Teile der Zerlegung durch NaNs
unbrauchbar geworden sind- die restlichen Teile brauchbar.
Beispielsweise dann, wenn man nur an den größten/kleinsten oder
mittleren Eigenwerten oder -Vektoren interessiert ist. Oder aber es wird
anhand der Struktur des Ergebnisses (inklusive der durch NaNs markierten
Elemente) eine Reparametrierung ausgeführt, um im nächsten
Iterationsschritt besser dazustehen.
Differentialgeometrie ist ja auch Geometrie, gelle?
Das findet natürlich nicht auf einem AVR und auch nicht auf einem ARM
statt. Und statt C ist da eher Fortran verbreitet. Aber Seltenheitswert
hat es deshalb nicht.
Viele Grüße
W.T.
P.S.: Das ist der Bereich, wo ich mich wohler fühle. Deswegen stelle ich
ja auch immer so blöde Fragen zum AVR :-)
Walter Tarpan schrieb:
[...]
> Bislang war ich davon ausgegangen, daß float nach IEEE 754 definiert> ist, wo eine Division durch Null -Inf oder Inf liefert - also mitnichten
Jein. Wenn Du das in Assembler tust und die zuständigen Flags im
benutzten Prozessor entsprechend gesetzt hast...
> eine problematische Operation ist,
Division durch 0 unproblematisch? Noch nie sowas gehört...
> Deswegen die Frage an die GCC-Fraktion (GCC, ARM-GCC, AVR-GCC): Ist die> Division durch float Null problematisch? Undefiniert?
Undefiniert, sagt ISO/IEC 9899:1999 (aka ANSI C99) 6.5.5. Absatz 5.
> Ist ein float hier gar nicht nach IEEE 754 definiert?
Nicht notwendigerweise, wahrscheinlich nur wenn die Hardware IEC
60559:1989 (vorher auch mal ANSI/IEEE 754−1985 genannt) kann und in
jedem Fall nur wenn die C-Implementation anzeigt dass sie das so tut.
Dazu steht eine Menge Zeugs im (normativen) Anhang F. Es duerfte oft das
Aendern von Compilerflags/Runtime-Konfiguration involvieren soweit ich
mich erinnere.
Natuerlich kann der aktuelle C-Standard wieder andere Dinge sagen...
Sieh an. Ich bin beim K&R heute endlich bis Seite 193 gekommen und da
steht:
"Die Behandlung von [...] Division durch Null [...] ist in der Sprache
nicht definiert. [...] Die Behandlung von Division durch Null und allen
Ausnahmen bei Gleitpunktrechnung variiert zwischen verschiedenen
Implementierungen; manchmal kann sie durch nicht-standardisierte
Bibliotheksfunktionen beeinflußt werden."