• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[DISKUSSION] Fließkomma- und Ganzzahlen in JavaScript

mikdoe

Moderator
Dieser Thread ist ein Extrakt aus Thread http://forum.jswelt.de/javascript/57908-richtig-runden.html

Ich mache solche Rechnung bewußt niemals in JS, weil ich auf den Browser und seine Rechnerei keinen Einfluss habe. Daher ist mein Mathematik-JS extrem beschränkt.
Aber wenn ich müsste würde ich wohl mit soetwas wie z.B. Math.floor() die Ganzzahl eines Wertes ziehen und danach den Dezimalpunkt in der Zahl suchen mit soetwas wie indexOf() und abhängig von der dritten Stelle nach dem Dezimalpunkt (bei >4 soweit überhaupt vorhanden) zu meiner Ganzzahl eine addieren.
Und ab diesem Punkt würde ich intern nur noch mit dieser Ganzzahl weiter rechnen und erst bei der Ausgabe (so spät wie möglich) wieder durch 100 dividieren zwecks Anzeige.
Dein Beispiel 24,37 ist übrigens ungeeignet da es nicht gerundet werden muss. 24,375 als Ergebnis einer Rechnung wäre das bessere Beispiel. Da müsste dann 2438 als Ganzzahl rauskommen.

Aber eine Warnung noch: Das garantiert auch nicht in allen Fällen den Erfolg! Auch bei der Umwandung in eine Ganzzahl können Fehler passieren. Selbst die Ur-Serversprachen wie z.B. Perl kommt bei solchen Aktionen (wg. fehlendem internen Typecast) manchmal an ihre Grenzen.
Wenn es hier also um was geht, mach das weder mit JS noch mit Perl sondern in Sprachen die rechnen können, wie z.B. die C-Dialekte (hab ich mir sagen lassen).
 
Zuletzt bearbeitet:
AW: Richtig runden.

Ich mache solche Rechnung bewußt niemals in JS, weil ich auf den Browser und seine Rechnerei keinen Einfluss habe. Daher ist mein Mathematik-JS extrem beschränkt.
Aber wenn ich müsste würde ich wohl mit soetwas wie z.B. Math.floor() die Ganzzahl eines Wertes ziehen und danach den Dezimalpunkt in der Zahl suchen mit soetwas wie indexOf() und abhängig von der dritten Stelle nach dem Dezimalpunkt (bei >4 soweit überhaupt vorhanden) zu meiner Ganzzahl eine addieren.
Warum so ein Geschwurbel?
Das macht doch keinen Sinn.
Und ab diesem Punkt würde ich intern nur noch mit dieser Ganzzahl weiter rechnen und erst bei der Ausgabe (so spät wie möglich) wieder durch 100 dividieren zwecks Anzeige.
Dein Beispiel 24,37 ist übrigens ungeeignet da es nicht gerunden werden muss. 24,375 als Ergebnis einer Rechnung wäre das bessere Beispiel. Da müsste dann 2438 als Ganzzahl rauskommen.
Das Problem bei seinem Beispiel ist es, dass er diese Menge aufteilen will, in 77% und zweimal 11,5%. Mathematisch geht das ohne Probleme. Das Problem ist, dass es Geld nur in Cent gibt.
 
AW: Richtig runden.

Warum so ein Geschwurbel?
Das macht doch keinen Sinn.
Vielleicht hier nicht unbedingt. Aber generell schon. Ich beschäftige mich schon länger mit diesem Thema - zwar nicht in JS - aber da kann man lustige Dinge erleben.

Das Problem bei seinem Beispiel ist es, dass er diese Menge aufteilen will, in 77% und zweimal 11,5%. Mathematisch geht das ohne Probleme. Das Problem ist, dass es Geld nur in Cent gibt.
OK, aber wenn schon beim Runden nicht richtig gerechnet wird, wird es am Ende nie stimmen.
 
AW: Richtig runden.

Weil es in Perl aufgrund des fehlenden Typecast diverse Probleme sowohl beim int()'en als auch beim Rechnen und Darstellen gibt.
Wie das genau in JS ist weiß ich nicht, habe ich nicht untersucht.
Auf jeden Fall tun es in Perl einfache Lösungen nicht. :)
Und der Ansatz von Korbinian kam mir einfach nur bekannt vor.
 
AW: Richtig runden.

Dann müßtest du mir doch erklären können, was er darstellt?
Ich sehe nur Regexe und Stringverarbeitung. Hab es nicht tiefergehend analysiert.

wieso fehlt in Perl der typecast? Im gegenteil, in Perl wird ähnlich umgewandelt wie in JS.
Ja?
Warum bringt dieses Script denn zwar 57 aber "nein" als Ergebnis?
Code:
#!/usr/bin/perl
use strict;
use warnings;
my $a = .57*100;
print "57 == $a? ".($a==57?'ja':'nein')."\n";
 
AW: Richtig runden.

was wird denn das für eine lustige diskussion?

Ich sehe nur Regexe und Stringverarbeitung.
hab ich auch schon mal gesehen


Warum bringt dieses Script denn zwar 57 aber "nein" als Ergebnis?
weil .57 binär nicht darstellbar ist (jedenfalls nicht mit den zur verfügung stehenden bits, ob überhaupt will ich jetzt nicht ausrechnen)
aber gerundet - und darum geht es ja - stimmt alles

Code:
var a = (.57*100).toFixed(0);
  alert("" + ("57" == a) + " " + a);
 
AW: Richtig runden.

Warum sollten das drei Stellen nach dem Komma sein wenn du nur zwei angibst? Es sollte 4.93 sein und ist es auch.
- 'tschuldigung. Hatte mich vertippt. Meinte natürlich 4.93 - aber deine Funktion spuckt 4.94 aus.
Das Problem ist, die Länge der Zahl. Soviele Stellen kannst du mit JS nicht darstellen. alert(4.9349999999999999); rundet bereits auf 4.935 was aber auch richtig ist.
Natürlich kann JS soviele Stellen darstellen Number.MIN_VALUE ist 5e-324 (und z.B. 1st 1.0000000000000001 !== 1.0000000000000002). Es ist nur an der Grenze und wird intern genauso gespeichert wie 4.935 - zu welcher Zahl jetzt "richtig" gerundet werden soll, ist jetzt fraglich.
Auch "rundet" alert(4.9349999999999999.toFixed(16)) nicht mehr zu 4.9350...

Um das Ganze auf einen Punkt zu bringen: JS hat ein Zahlenformat, das Dezimalzahlen mit Fließkommaanteil nicht immer korrekt repräsentieren kann. Das kann schnell zu unerwartetem Verhalten führen (ich denke mal das Bekannteste ist 0.1 + 0.1 + 0.1 !== 0.3). ABER Ganzzahlen können 100%ig korrekt gespeichert werden (wenn sie zwischen -2^31 und 2^31-1 - also -2147483648 und 2147483647). Also wenn es um Geld geht immer in Ganzzahlen arbeiten (außer man hat Geldbeträge über 2.1 Milliarden - aber dann sollte man sowieso nicht mit JS arbeiten...).

Die Funktion war einfach nur an die Originalfrage angelehnt - dort wurde Geld nach einem bestimmten Prozentanteil verteil. Das habe ich nachgebildet (ist das Beispiel mit den 11.5%).
 
Zuletzt bearbeitet von einem Moderator:
AW: Richtig runden.

z.b. so:
Code:
sprintf '%0.0f', .57*100
Ja, meine Frage war retorisch. Das Beispiel sollte zeigen, dass man eine scheinbar einfache Sache noch extra behandeln muss.
Soviel zum Thema "immer mit Ganzzahlen arbeiten". Selbst bei einer einfachen Multiplikation muss man damit rechnen, dass die Programmiersprache intern anders speichert als man aufgrund der print Ausgabe glaubt.
Das meinte ich mit den Überraschungen, die man hier und da erlebt :)
Daher: Auch das Arbeiten mit Ganzzahlen ist kein Allheilmittel.
Ich weiß allerdings nicht, ob es diese Fallgrube auch in JS gibt. Würde mich mal interessieren, ob da jemand mehr zu weiß.

Ich dachte es käme dir bekannt vor?
Grob, ja. Nicht im Detail.

ABER Ganzzahlen können 100%ig korrekt gespeichert werden (wenn sie zwischen -2^31 und 2^31-1 - also -2147483648 und 2147483647).
Davon geht man bei Perl wahrscheinlich auch aus, ist aber nicht so, wie das Beispiel beweist.
Würdest du für diese Aussage deine Beine ins Feuer legen, Korbinian? :)
 
AW: Richtig runden.

- 'tschuldigung. Hatte mich vertippt. Meinte natürlich 4.93 - aber deine Funktion spuckt 4.94 aus.
Natürlich kann JS soviele Stellen darstellen Number.MIN_VALUE ist 5e-324 (und z.B. 1st 1.0000000000000001 !== 1.0000000000000002). Es ist nur an der Grenze und wird intern genauso gespeichert wie 4.935 - zu welcher Zahl jetzt "richtig" gerundet werden soll, ist jetzt fraglich.
Auch "rundet" alert(4.9349999999999999.toFixed(16)) nicht mehr zu 4.9350...

JS hat ein Zahlenformat, das Dezimalzahlen mit Fließkommaanteil nicht immer korrekt repräsentieren kann.
Das hat aber nichts mit JS zu tun. das ist so definiert in allen Sprachen! http://de.wikipedia.org/wiki/IEEE_754
Ich wüsste jetzt auch keine Sprache, die von Hause aus mehr als 64-Bit Gleitkommazahlen anbietet.

Das kann schnell zu unerwartetem Verhalten führen
eigentlich nicht. 1/3, 2/55, ... kannst du auch im dezimalen nicht als Gleitkommazahlen darstellen. und jeder der mehr als Briefe am rechner schreibt sollte eigentlich wissen wie gleitkommazahlen binär dargestellt werden und sich nicht wundern, daß +0 != -0 ist.

EDIT: hier kann man sich schön die darstellung als 32-Bit/64-Bit/... Gleitkommazahl im Speicher ansehen.
 
Zuletzt bearbeitet von einem Moderator:
AW: Richtig runden.

Soviel zum Thema "immer mit Ganzzahlen arbeiten".
du arbeitest ja nicht mit ganzzahlen. dein problem ist ja nicht die multiplikation, sondern .57.


Daher: Auch das Arbeiten mit Ganzzahlen ist kein Allheilmittel.
http://www.youtube.com/watch?v=tPfnEByx9r0


Ich weiß allerdings nicht, ob es diese Fallgrube auch in JS gibt. Würde mich mal interessieren.
das ist sprachunabhängig
 
AW: Richtig runden.

Davon geht man bei Perl wahrscheinlich auch aus, ist aber nicht so, wie das Beispiel beweist.
Welches Beispiel? Dein Beispiel war ja eines, wo du zeigst wie man es nicht macht. Du musst natürlich auch eine Zahl explizit in eine Ganzzahl umwandeln und das macht dein Beispiel nicht.

- 'tschuldigung. Hatte mich vertippt. Meinte natürlich 4.93 - aber deine Funktion spuckt 4.94 aus.
.toFixed(2) auch.

Natürlich kann JS soviele Stellen darstellen Number.MIN_VALUE ist 5e-324 (und z.B. 1st 1.0000000000000001 !== 1.0000000000000002). Es ist nur an der Grenze und wird intern genauso gespeichert wie 4.935 - zu welcher Zahl jetzt "richtig" gerundet werden soll, ist jetzt fraglich.
Auch "rundet" alert(4.9349999999999999.toFixed(16)) nicht mehr zu 4.9350...
Bei mir sieht das anders aus: alert(4.9349999999999999) => 4.935 oder
zahl = 4.9349999999999999;
alert(4.935 === zahl); // => true

Wobei diese problematik wohl nur akademischen Wert haben dürfte. Da diese Zahlen bei der Berechnung von Währungen in der Realität nicht vorkommen sollten.
 
AW: Richtig runden.

du arbeitest ja nicht mit ganzzahlen. dein problem ist ja nicht die multiplikation, sondern .57.
Na ja, nicht ganz. Das Problem ist, dass ich nach einer Mulitiplikation von .57 mit 100 laut print in der Variable 57 stehen habe. Das ist ein erwartetes Ergebnis.
Dennoch schlägt 57==57 fehl. Denn intern speichert Perl nicht 57. Es ist also nur scheinbar eine Ganzzahl. Und sie wird erst nach sprintf() zu dieser.
Wenn sie dann mal wirklich eine Ganzzahl ist (nach sprintf()) dann mag es ja im weiteren Verlauf ok sein. Aber ich würde das schon als Fallstrick bezeichnen.


Sehr schön :)

das ist sprachunabhängig
Was genau jetzt? Dass die Wurzel aus 2 irrational ist oder dass mein gezeigtes Beispiel nur scheinbar eine Ganzzahl ist?
 
AW: Richtig runden.

Dein Beispiel war ja eines, wo du zeigst wie man es nicht macht.
Jau.

Du musst natürlich auch eine Zahl explizit in eine Ganzzahl umwandeln und das macht dein Beispiel nicht.
Und das meinte ich mit Typecast. Würde ein vorhandenes Typecast nicht von selbst hieraus intern eine Ganzzahl machen?
Sagen wir mal so, ob Typecast dafür jetzt der 100 % richtige Ausdruck ist, weiß ich nicht.
Aber irgend wie ist das doch auf den ersten Blick verwirrend für manche, oder nicht?
 
AW: Diskussion zum Speichern/Anzeigen von Fließkomma- und Ganzzahlen

Dieser Thread ist ein Extrakt aus Thread http://forum.jswelt.de/javascript/57908-richtig-runden.html

Ich mache solche Rechnung bewußt niemals in JS, weil ich auf den Browser und seine Rechnerei keinen Einfluss habe. Daher ist mein Mathematik-JS extrem beschränkt.
Aber wenn ich müsste würde ich wohl mit soetwas wie z.B. Math.floor() die Ganzzahl eines Wertes ziehen und danach den Dezimalpunkt in der Zahl suchen mit soetwas wie indexOf() und abhängig von der dritten Stelle nach dem Dezimalpunkt (bei >4 soweit überhaupt vorhanden) zu meiner Ganzzahl eine addieren.
Und ab diesem Punkt würde ich intern nur noch mit dieser Ganzzahl weiter rechnen und erst bei der Ausgabe (so spät wie möglich) wieder durch 100 dividieren zwecks Anzeige.
Dein Beispiel 24,37 ist übrigens ungeeignet da es nicht gerundet werden muss. 24,375 als Ergebnis einer Rechnung wäre das bessere Beispiel. Da müsste dann 2438 als Ganzzahl rauskommen.

Aber eine Warnung noch: Das garantiert auch nicht in allen Fällen den Erfolg! Auch bei der Umwandung in eine Ganzzahl können Fehler passieren. Selbst die Ur-Serversprachen wie z.B. Perl kommt bei solchen Aktionen (wg. fehlendem internen Typecast) manchmal an ihre Grenzen.
Wenn es hier also um was geht, mach das weder mit JS noch mit Perl sondern in Sprachen die rechnen können, wie z.B. die C-Dialekte (hab ich mir sagen lassen).

Du bringst eine Menge durcheinander. Zum einen die Problematik der Darstellung von Gleitkommazahlen und dann die Genaugkeit der Berechnungen.

Die Darstellung einer Fließkommazahl mit einer festen Anzahl von Nachkommastellen kann immer problematisch sien, egal mit welcher Programmiersprache du das machst. Und die Genauigkeit einer Sprache hängt von deren internen Zahlenformat ab. Um die Genauigkeit zu erhöhen, gibt es in Perl auch diverse Module. Mit JS ist das nicht möglich. Aber um mit Währungen zu arbeiten ist eine solche Genauigkeit auch überflüssig, da du nur zwei Stellen brauchst, um dabei die interne Darstellung zu vermeiden wandelst du diese in Ganzzahlen um. Fertig.

Was ist denn ein interner Typecast?
 
Zurück
Oben