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

Richtig runden.

Natürlich ist .toFixed korrekt.

Das Problem ist, dass man die Zahlen, die scheinbar falsch gerundet werden, nicht in binären Fließkommanzahlen darstellbar sind:
Code:
alert(4.935.toFixed(20))
diese gespeicherte Zahl wird dann richtig gerundet.

Nun gibt es aber auch Zahlen, die mit der neuen Funktion vom schlauen falsch gerundet werden:
Code:
4.9349999999999999.fix(2) // sollte eigentlich 4.93 sein
.

Da aber 0.5 in binären Fließkommazahlen darstellbar ist (0.1b) hat man da viel weniger Probleme, wenn man mit Ganzzahlen (also in Cent) arbeitet.

Ich würde dieses "Verteilungsproblem" ja so lösen (wenn man unbedingt Strings als Parameter übergeben können muss):
Code:
function splitProfit(value, parts){
	if (typeof value === "string"){
		value = Math.round(parseFloat((value + "00").replace(/(.|,)(\d\d)/, "$2.")));
	}
	
	var remaining = value;
	var ret = [];
	for (var i = 0; i < parts.length; i++){
		if (typeof parts[i] === "string"){
			parts[i] = parseFloat(parts[i].replace(",", ".")) / 100;
		}
		var part = Math.round(value * parts[i]);
		remaining -= part;
		ret.push(part);
	}
	ret.push(remaining);
	return ret;
}

alert(splitProfit("24,37", [0.115, "11,5"]));
 
Zuletzt bearbeitet:
Ja, die Richtung von kkapsner schwebte mir auch vor.
Sieht auch meiner Perl Funktion ähnlich, die ich benutze.
 
Nun gibt es aber auch Zahlen, die mit der neuen Funktion vom schlauen falsch gerundet werden:4.9349999999999999.fix(2) // sollte eigentlich 4.934 sein
Warum sollten das drei Stellen nach dem Komma sein wenn du nur zwei angibst? Es sollte 4.93 sein und ist es auch.
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.
 
Hallo liebe Gemeinde,

ich habe heute den Tag über mal über eure Vorschläge und Denkanstöße nachgedacht und mir nun folgendes ausgetüftelt. Habe im Prinzip mit meiner Berechnung neu angefangen.

Code:
function gewinn_ausrechnen_neu(netto, prozent1, prozent2, prozent3, feld1, feld2, feld3) {
	rechenzahl0 = netto.replace(",",".") * 100; //Komma 2 stellen nach rechts verschieben
	rechenzahl0a = parseInt(rechenzahl0); //String in Zahl zum rechnen umwandeln
	prozentzahl1 = prozent1.replace(",",".");
	prozentzahl2 = prozent2.replace(",","."); 
	prozentzahl3 = prozent3.replace(",",".");
	rechenergebnis0 = (rechenzahl0a/100)*prozentzahl1; //Prozent ausrechen -> rechenzahl 1-3 == Prozentsatz
	rechenergebnis1 = (rechenzahl0a/100)*prozentzahl2; //Prozent ausrechen -> rechenzahl 1-3 == Prozentsatz
	rechenergebnis2 = (rechenzahl0a/100)*prozentzahl3; //Prozent ausrechen -> rechenzahl 1-3 == Prozentsatz
	rechenergebnis00 = rechenergebnis0/100; //Komma 2 stellen nach links verschieben
	rechenergebnis11 = rechenergebnis1/100; //Komma 2 stellen nach links verschieben
	rechenergebnis22 = rechenergebnis2/100; //Komma 2 stellen nach links verschieben
	a = rechenergebnis00.toFixed(2); //Auf 2 stellen gerundet
	b = rechenergebnis11.toFixed(2); //Auf 2 stellen gerundet
	c = rechenergebnis22.toFixed(2); //Auf 2 stellen gerundet
	d = parseFloat(a)+parseFloat(b)+parseFloat(c); //Ergebnis Summe der verteilung
	e = rechenzahl0/100 //Netto-Summe
	f = d.toFixed(2) // Ergebnis Summer der verteilung gerundet
	if (e != f) { //Prüfe ob Differenz zwischen Netto und Summe Verteilung
		x = e - f;
		if (x < 0) {x = x * -1} //Negative zahl Positiv wandeln
		y = x.toFixed(2);
		aa = parseFloat(a)+parseFloat(y); //If differenz dann Differenz der angezeigten Summe im Feld 1 hinzufügen
	} else {
		aa = a; //If not Differenz Feld 1 = Verteilung Feld 1
	}

	if (document.getElementById(feld1)) { //Ausgabe an Feld 1-3
		document.getElementById(feld1).value = aa.toFixed(2);
		document.getElementById(feld2).value = b;
		document.getElementById(feld3).value = c;
	} else {
		$(this).ajaxStop(function() {
			document.getElementById(feld1).value = aa.toFixed(2);
			document.getElementById(feld2).value = b;
			document.getElementById(feld3).value = c;
		});
	}
}

Egal welche Summe, bzw welche Verteilung ich eingebe, kommt ein richtiges Ergebnis raus. Ich berechne nun die Differenz zwischen den beiden Summen und füge diese dem ersten Verteiler zu. Somit haben die anderen beiden Felder zwar das nachsehen, ist aber kaufmännisch richtig. Denn wie ihr bereits sagtet, 1 Ct lässt sich nicht aufteilen! :D

Falls ihr noch Unstimmigkeiten findet, oder falls ich etwas unnötig gemacht habe, bitte raus damit. Vielen Dank trotzdem für die Hilfe!

Tom
 
@SaFle: In deinem Code "verschiebst" du das Komma, indem du mit 100 multiplizierst - das ist nicht so glücklich, da du vorher einen impliziten Cast zu Number hast und dort schon "Rundungsfehler" auftreten können. Schau' dir einfach mal in meinem Code an, wie ich das Komma verschoben habe. Wenn du's nicht verstehst: frag' konkret nach.
 
Zuletzt bearbeitet von einem Moderator:
Zum Thema Runden: im Javascript 2015 gibt es eine neue Funktion namens Math.trunc()

Aber Vorsicht, das können noch nicht alle Browser.

Schon jemand mal damit rum gespielt, ob das auch aus kaufm. Sicht passt?
 
Nein, macht es nicht.

parseInt(string, radix); erwartet einen String und es kann das Zahlensystem für den Ziewert angegeben werden.
Math.trunc(x); erwartet einen numerischen Float und schneidet den Nachkommateil ab. Da wird in der Tat nicht gerundet.

Bei der gesamten Diskussion habe ich habe ich das Gefühl, das die Grundlagen von Gleitkommazahlen einigen nicht bekannt sind.
Gleitkommazahlen sind ungenau ! Das liegt an der begrenzten Mantisse. Es werden ca 3,3 Bits für die Darstellung einer Dezimalstelle benötigt.
Ist die Gleitkommazahl 32 Bit dann sind i.d.R1 Bit Vorzeichen, 8 Bit für den Exponenten und 23 Bit für die Mantisse vorhanden. Es muss also notwendigerweise
abgeschnitten werden. Das gilt für alle Zahlen die grösser als der Signifikanzbereich sind und/oder deren Nachkommateil keine Potenz von 2 ist.
Der Signifikanzbereich einer float liegt also zwischen 6 und 7 Stellen. Bei einer Double sind es ca 15 Stellen.
Ausserdem hat man ein Problem , wenn die Nachkommastellen keine Potenz von 2 sind. So ist z.B. 0,4 nicht exakt als Gleitkommazahl darstellbar.

Es hat schon seinen Grund, warum früher viel in COBOL programmiert wurde. Dort wird Dezimalarithmetik verwendet.
Tja, 1970 haben wir das noch in den Grundlagen der EDV vermittelt.

Gruß

Detlef
 
Nein, macht es nicht.
Doch macht es schon... schau' dir die Ergebnisse an. Bzw. zeig' mir einen Fall, wo sich die beiden Funktionen unterschiedlich verhalten. (Ausgenommen natürlich Fällen, in denen man einen anderen Wert als 10 für den Radix-Parameter übergibt)

PS: OK parseInt(-0) ist 0 und Math.trunc(-0) ist -0... aber wann ist dieser Fall wirklich relevant?
 
also ich nehme meine aussage erst mal wieder zurück, da schon toString die -0 wandelt.
Es gibt in JS nur einen Zahlentyp: Float.
in js gibt es leider nur den Zahlentyp number, dem man erst mal nicht ansieht, was er intern eigentlich ist. ich hätte jetzt einen variant erwartet, aber finde in der spec allerdings auch keine "eindeutige" vorschrift. wenn man mal genauer drüber nachdenkt, wäre es aber tatsächlich das einfachste einfach einen double als internen datentyp zu nehmen, da überall wo man aufpassen müsste sowieso eine konvertierung vorgeschrieben ist.
 
Das ist schon spezifiziert...
ECMA-262 schrieb:
double-
precision 64-bit format IEEE 754 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic

Aber du hast Recht - intern könnte natürlich jeder JS-Interpreter das so machen, wie er will.
 
Zurück
Oben