PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Division


dark_shale
2003-01-13, 18:43:40
Ich habe folgendes Problem:

Wieso bekomme ich bei diesem Programm immer ein ungenaues Ergebnis?

zB:


const float hundert = 100;


void main()
{
float eingabe,zahl;
int i;

scanf("%f",&eingabe);

zahl = eingabe;
printf("Herkömlich: \n");
for (i=1;i<=15;i++)
{
printf("zahl = %2.40f\n",zahl);
zahl = zahl / 100;
}
printf("zahl = %2.40f\n\nAssembler: \n",zahl);

zahl = eingabe;
for(i=1;i<=15;i++)
{
printf("zahl = %2.40f\n",zahl);
__asm
{
FINIT
fld hundert
fld zahl
fdiv st(0),st(1)
fstp zahl
}
}
printf("zahl = %2.40f\n",zahl);
getch();
}




Ich bekomme sowohl mit Assembler als auch mit C einen ungenauen Wert.
Ich habe es schon auf einem AMD, Intel, Apple(nur in C) probiert.

Ich schätze mal, dass es normal ist, aber aus Interesse woran liegt das?

Matrix316
2003-01-13, 20:14:21
liegt am Datentyp float - mit Double wirds etwas genauer ;)

(ich weiß, dass dir das auch nicht viel hilft)

PS.: Vielleicht haben Float Zahlen nicht so viele Zeichen hinter dem . so dass bei jeder Rechnung irgendwelche ungenauen Werte von irgendwoher sich in die Variable verirren.

dark_shale
2003-01-13, 20:46:20
thx

aber mit double hab ich es auch schon probiert!

Weiß jemand genau wodurch dieses Problem :pacman: entsteht?

Xmas
2003-01-13, 22:06:12
Was meinst du mit "ungenauem Wert"?

Mit Eingabe 1 bekomme ich folgenden Endwert:
0.0000000000000000000000000000009999999091

Wenn ich float durch double ersetze, kommt das am Ende heraus:
0.0000000000000000000000000000010000000000

Also double ist schon noch ein Stück genauer. Dass nicht immer genau eine 1 herauskommt liegt daran dass binär gerechnet wird. Eine Division durch 100 zieht also nicht nur vom Exponenten 2 ab.

Gnafoo
2003-01-22, 23:38:37
Originally posted by dark_shale
zahl = zahl / 100;

btw. zahl = zahl / 100; geht auch kürzer als zahl/=100;
is aber geschmackssache :)

wenn man deine zahl immer wieder teilt, bekommt man irgendwann
gezwungenermaßen eine rechenungenauigkeit. wenn man den wert
weiterhin teilt, wird diese ungenauigkeit immer größer ..
deswegen wäre glaube ich geschickter:

int divisor=100;
float wert;
for(int i=0; i<15; i++) {
divisor*=divisor;
wert=ergebnis/(float)divisor;
printf("%2.40f\n", wert);
}

bin mir aber nicht ganz sicher..
(ich glaub in art of assembly war das beim fp-abschnitt
ganz gut erklärt .. wenn es dich interessiert kannst du ja
mal nachschauen .. einfach mit google danach suchen ..
bin mir aber nicht ganz sicher)

zeckensack
2003-01-23, 14:15:23
Floats sind Summenreihen von Zweierpotenzen. Der Rechner speichert ein Vorzeichen, eine binäre Mantisse (zB 1.001100111 ...) und einen Zweier-Exponenten, der die Wertigkeit des ersten Bits vor dem (Binär-)Punkt angibt.

(dieses wird btw auf aktuellen Rechnern nicht gespeichert, da angenommen wird daß es immer gesetzt ist. Deswegen heißt's auch 'Hidden Bit'. Google fragen: IEEE-754. Das ist der Floating-Point-Standard, den alle aktuellen CPUs implementieren.)

Dh daß 100.0 (=64+32+2), 16.0, 1.375 (=1 + 0.25 + 0.125), 0.25 ... 1/(2 'hoch' 20) etc genau dargestellt werden können. 0.1 ist aber nicht verlustfrei in eine Summe von Zweierpotenzen zerlegbar.

zeckensack
2003-01-23, 14:16:22
Originally posted by Der Tod

btw. zahl = zahl / 100; geht auch kürzer als zahl/=100;
is aber geschmackssache :)

wenn man deine zahl immer wieder teilt, bekommt man irgendwann
gezwungenermaßen eine rechenungenauigkeit. wenn man den wert
weiterhin teilt, wird diese ungenauigkeit immer größer ..
deswegen wäre glaube ich geschickter:

int divisor=100;
float wert;
for(int i=0; i<15; i++) {
divisor*=divisor;
wert=ergebnis/(float)divisor;
printf("%2.40f\n", wert);
}

bin mir aber nicht ganz sicher..
(ich glaub in art of assembly war das beim fp-abschnitt
ganz gut erklärt .. wenn es dich interessiert kannst du ja
mal nachschauen .. einfach mit google danach suchen ..
bin mir aber nicht ganz sicher)
Sollte das nicht so aussehen ?int divisor=100;
float wert,ergebnis;
for(int i=0; i<15; i++) {
divisor*=divisor;
ergebnis=wert/(float)divisor;
printf("%2.40f\n", ergebnis);
}

Gnafoo
2003-01-23, 15:37:34
nur wenn man die zwischenergebnisse nicht sehen will ..
und da das anfangsprogramm die ausgegeben hat, hab ichs
so übernommen ..

zeckensack
2003-01-23, 15:43:50
Originally posted by Der Tod
nur wenn man die zwischenergebnisse nicht sehen will ..
und da das anfangsprogramm die ausgegeben hat, hab ichs
so übernommen .. Ah, jetzt, ja =)
Ich denke aber immer noch, daß es nicht ganz korrekt war. Ich hab's nochmal editiert.

Gnafoo
2003-01-23, 17:28:55
ups ja klar stimmt :)
so kommen immer diese unerklärlichen fehler zustande..
hmm ..

:D