Seite 1 von 2

0*(1/0-1)=-2147483648

Verfasst: 18.01.2005 16:35
von computerkranker
Ich hatte gerade einen Fehler in meinen Programm, weil ich vergessen hatte die Null abzufangen(untere Beispiel "a"). Klar sollte man das tun bei Div durch Null, aber das Ergebniss ist gerundet trotdem sehr verwirrend.
Eigentlich schon fast lustig das 0*irgendwas einen Wert ergibt. :mrgreen:

Code: Alles auswählen

a=0 
z=0
f.f=z*(1/a-1)
d.l=Round(f.f,0)
Debug f.f
Debug Round(f.f,0)
Debug d.l

Verfasst: 18.01.2005 17:10
von ts-soft
Viel schlimmer ist, das der Debugger keine Fehlermeldung ausgibt. Da kann es doch passieren, das man mit diesen komischen Werten weiterrechnet.

Verfasst: 18.01.2005 17:56
von benny
Tja, man sollte halt immer im Hinterkopf haben,daß das Rechnen mit floats
nicht immer 100%ig genau ist.

Denkt an folgenden Thread :

http://robsite.de/php/pureboard-archiv/ ... ght=#42421

Verfasst: 18.01.2005 18:12
von freedimension
benny hat geschrieben:Tja, man sollte halt immer im Hinterkopf haben,daß das Rechnen mit floats
nicht immer 100%ig genau ist.
Naja, zumindest die 0 lässt sich sehr genau als Float darstellen und 0 * ungenau ist immer noch 0 ;)

Verfasst: 18.01.2005 19:02
von GPI
freedimension hat geschrieben:Naja, zumindest die 0 lässt sich sehr genau als Float darstellen und 0 * ungenau ist immer noch 0 ;)
Nein nicht zwingend (wenn ich mich richtig errinnere). Besonders wenn mit den Ergebnis aus 1/0 gerechnet wird...

Floats kann damit teilweise rumhantieren. Sollte man in Hinterkopf haben...

Verfasst: 18.01.2005 19:11
von DarkDragon
Ähh, die ergebnisse kann man begründen. Die ersten zwei sind sogenannte NaN (Not a Number) werte. Das dritte ist wohl einfach die bytewerte des floats in einen int teleportiert und das ganze aufgerundet eben.

Deshalb braucht man die c++ funktion isnan(). Danilo hat eine funktion geschrieben, allerdings funktioniert die nicht immer bei mir.
Danilo hat geschrieben:Als erstes mußt Du den Float-Wert mit FLD (Fpu LoaD) in das
Register ST(0) laden, danach kommt dann das FXAM.

FXAM setzt die Bits C0, C1, C2 und C3 im Status-Register
der FPU.
Im Status-Register (ein Word, also 16-Bit) findest Du diese
Bits wie folgt:
Code:
Bit 8 - C0-Flag
Bit 9 - C1-Flag
Bit 10 - C2-Flag
Bit 14 - C3-Flag

Das Status-Register kannst Du in eine 16-Bit-Speichervariable
laden, oder direkt ins CPU-Register AX: FSTSW AX

Nun hast Du den Status in AX und kannst die oben angegebenen
Bits auswerten. FXAM gibt dabei folgendes zurück:
Code:
| C0 | C2 | C3 |
-----+----+-----
| 0 | 0 | 0 | Nicht unterstützt
| 1 | 0 | 0 | NaN
| 0 | 1 | 0 | Normale endliche Zahl
| 1 | 1 | 0 | Unendlich
| 0 | 0 | 1 | Null
| 1 | 0 | 1 | Leer
| 0 | 1 | 1 | Denormalisierte Zahl
-----+----+-----

Im C1-Flag steht immer das Vorzeichen.

Deine Zahl in ST(0) mußt Du natürlich wieder entfernen.

Probier mal damit:
Code:
;
; by Danilo, 29.07.2004 - german forum
;
Procedure IsNaN(float.f)
; check float for NaN
; return: 1 = Not-a-Number
; 0 = no Not-a-Number
DisableDebugger
!FLD dword [esp]
!FXAM
!FSTSW AX
!FSTP dword [esp] ; !FFREE ST0
; !FINCSTP
!AND dword EAX,100h
!SHR dword EAX,8
ProcedureReturn
EnableDebugger
EndProcedure

Debug IsNaN( 0.0 )

Debug IsNaN( 2.0 )
Debug IsNaN( -99999999.9 )
Debug "-----"

a.f = 0.1
b.f = 0.0
Debug IsNaN( a / b )
Debug a / b

a = 99999999.9
b = 99999999.9
c.f = a*b*a*b*a*b
Debug Bin(IsNan( c ))
Debug c

PokeL(@a,$FFFFFFFF)
Debug IsNaN( a )
Debug a

Ich bin mir gerade etwas unsicher ob FFREE + FDECSTP
100%tig korrekt sind, wenn vorher noch andere Werte
auf dem Stack gespeichert wurden, deshalb der Kommentar
mit FSTP. Scheint aber so zu stimmen... icon7.gif

Im Moment gibt die Prozedur 1 zurück, wenn es eine NaN ist.
Das ist so wie bei Deiner ursprünglichen Prozedur.
Man kann aber auch noch die Zeile "!SHR dword EAX,8" weg-
lassen, dann gibt es immer $100 zurück wenn es eine NaN ist.
Der Check würde dann mit: If IsNaN( num.f ) trotzdem funktionieren.
Also 0 wenn es keine NaN ist und TRUE (d.h. alles ungleich 0)
wenn es eine NaN ist.

Wenn das so ist, dann musst Du die beiden Zeilen
Code:
!FFREE ST0 ;!FSTP dword [esp]
!FDECSTP ;

entfernen und durch das FSTP ersetzen. Deshalb hatte ich auch
beide Zeilen markiert, die gehören zusammen.

EDIT:
Ich seh grad des es FINCSTP statt FDECSTP sein müsste, dann dürfte
auch nichts durcheinander kommen. Da hat "Assembler gepackt" von
Joachim Rhode wieder mal einen Fehler, was es als Referenz
für mich langsam in Frage stellt. Hab da schon mehrere Fehler gefunden... icon_cry.gif
Mit dem FSTP geht es aber auf jedenfall korrekt, ich finds nur
blöd den Wert unnötigerweise wieder zurückzuschreiben.

Habe den obigen Code IsNaN() mal angepasst.
[EDIT] Mein problem habe ich mittels Variablenspeicher gelöst. Einfach mal die bytes aus den entsprechenden NaN werten peeken ;) .
[EDIT2] ;) nochwas: Debug Sqr(-1)

Verfasst: 18.01.2005 19:45
von TheShadow
1/0 ist gleich unendlich

und bei floats wird das durchaus ohne fehler akzeptiert - floats erlauben auch -0 und +0

ziemlich flexibel was?

Verfasst: 18.01.2005 19:49
von ts-soft
ähnelt meiner Signatur: Ganz viel Null ist fast ein bißchen Eins

Verfasst: 18.01.2005 22:32
von Froggerprogger
Der Fehler läßt sich reduzieren auf:

Code: Alles auswählen

a.l = 0
x.f = 1/a
y.l = Round(x,0)

Debug x
Debug y
Round muss schließlich für jeden Wert x irgendwas zurückliefern.
Falls x = NaN ist, liefert Round wieder NaN, falls ein Float erwartet wird. Wenn aber eine Int erwartet wird, dann hat man sich wohl dafür entschieden $80000000 zurückzugeben, was sehr vernünftig ist, da man dann leichter auf den Fehler aufmerksam wird, als das bei Rückgabewert 0 der Fall wäre.

Verfasst: 18.01.2005 23:43
von Deeem2031
Was mir grad auffällt, warum komm da...

Code: Alles auswählen

y.f = -2147483648
Debug y
... +2147483648.000000 raus?