| |||||||
Du magst keine Werbung? Wir auch nicht!
Einfach registrieren und die Werbung ist weg. Diese Nachricht sehen nur nicht registrierte Nutzer.
![]() |
| | LinkBack | Themen-Optionen | Ansicht |
| | #1 (permalink) |
| Neuer User Registriert seit: Sep 2001
Beiträge: 14
| Actioncript mal GENAU RECHNEN lassen ...
Hi! Es ist ja allgemein bekannt, dass Fließkommarechnungen nur begrenzt genau sind. Actionscript hat (glaube ich) die gleiche Genauigkeit mit float in Java. Ich habe nun das Problem, dass mir diese Genauigkeit nicht reicht, weil es zu unschönen Rundungsfehlern kommt. Gibt es IRGENDEINEN Weg genauer zu Rechnen mit Flash? Ich benutze auch gerne das neuste Flash, das neuste Actionscript oder irgendwelche "perversen" Tricks. Jedes Mittel ist Recht! |
| | |
| | #3 (permalink) |
| Techniker Registriert seit: Sep 2003 Ort: 64807
Beiträge: 16.321
|
die rechnen alle nach: ieee-754 http://de.wikipedia.org/wiki/IEEE_754 für astronomische berechnungen ist flash wohl nicht geeignet (wegen der fehlenden geschwindigkeit). falls doch, dann wirst du dir eigene rechenoperationen programmieren müssen: a) die zahlen in strings packen und so berechnen oder b) die zahlen aufteilen. z.b. 1111122222333334444455555 wird dann zu 12345 transformirt, wobei 1 = 11111 *10^20 darstellt 2 = 22222 *10^15 usw. um rundungsfehler in den brüchen zu verringern, keine dezimalstellen sondern die nachkommastelle als bruch speichern und dementsprechend berechnen.
__________________ die ultimative antwort auf alle programmierfragen: der debugger mfg h.g.seib www.SeibsProgrammLaden.de Geändert von hgseib (17-03-2006 um 22:19 Uhr) |
| | |
| | #4 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Wenn ich mit Geld rechnen muss, benutze ich z.B. immer Cent oder 10tel Cent als Basis. Nur für die Ausgabe mache ich dann daraus Euro. mfg. h
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D |
| | |
| | #5 (permalink) |
| Neuer User Registriert seit: Sep 2001
Beiträge: 14
|
@hgseib Wie ich geschieben hatte geht es mir um die Genauigkeit der Fließkommarechnung und nicht um ein Überschreiten des möglichen Zahlenbereichs. Und die Verwendung von IEEE 754 sagt ja nichts über die Genauigkeit aus. Zu deiner Möglichkeit a): Meinst du es macht Sinn zu versuchen sämtliche Rechenoperantionen für Strings nachzuimplementieren? Hat das schonmal jemand versucht? Mit Brüchen rechnen hat einen entscheidenden Nachteil: Man muss kürzen, also dividieren. Bisher muss ich das nicht. Daher habe ich Angst die Pest mit der Cholera auszutreiben. @hazy fantazy Die Idee hatte ich auch schon :-) Ich muss nur leider Geldbeträge mit Faktoren (z.B. 1,75) multiplizieren und dann auf 5 Cent abrunden. Genau da kracht es: Statt 10€ kommt 9.99999999...€ raus und dann rundet er auf 9.95€ ab :-/ Geändert von gammaomega (18-03-2006 um 13:53 Uhr) |
| | |
| | #6 (permalink) |
| Techniker Registriert seit: Sep 2003 Ort: 64807
Beiträge: 16.321
|
"..Und die Verwendung von IEEE 754 sagt ja nichts über die Genauigkeit aus.." doch, weil es neben dem zahlenbereich ja auch um die anzahl der signifikanten ziffern geht. also ab welcher stelle die zahlendarstellung abgebrochen wird. "..sämtliche Rechenoperantionen.." weiss ja nicht, was du machen willst, langen die 4 grundrechenarten, oder willst du auch wurzel, winkelfunktionen usw. genauer haben? "..Mit Brüchen rechnen hat einen entscheidenden Nachteil: Man muss kürzen, also dividieren.." genau das sollst du ja damit vermeiden! 157 / 17 = 9,2352941 == ungenau, weil nach den signifikanten ziffern weitere ziffern folgen müssten. 157 / 17 = 9 4/17 also drei anstatt einer variablen und es wird eben nicht gekürzt, sondern immer der ggT gesucht. ----------- aber, wie du erst jetzt verrätst willst du 'nur' mit geld rechnen. dann sollte ein vor-runden das 'problem' beheben: Code: Number.prototype.fuenfer = function() {
var rnd = Math.floor(Math.round(this*100)/5)/20;
return rnd == int(rnd) ? rnd+".00" : rnd*10 == int(rnd*10) ? rnd+"0" : rnd;
};
var a = 9.99999999999999999;
var b = 17.833;
var c = 99.977;
trace(a.fuenfer());
trace(b.fuenfer());
trace(c.fuenfer());
__________________ die ultimative antwort auf alle programmierfragen: der debugger mfg h.g.seib www.SeibsProgrammLaden.de Geändert von hgseib (18-03-2006 um 15:45 Uhr) |
| | |
| | #7 (permalink) |
| Neuer User Registriert seit: Sep 2001
Beiträge: 14
|
1.) IEEE 754 umfasst mehrere Formate und Genauigkeit. Daher ist die Aussage, dass Flash sich nach IEEE 754 richtet keine Aussage darüber welche Genauigkeit nun vorliegt. 2.) Eigentlich reichen +,-,* Aber die Multiplikation auf Strings nachzubauen stelle ich mir wenig spaßig vor. Machbar wäre es wohl.... 3.) Klar muss ich den ggT berechnen, dass ist ja easy. Aber danach muss ich ja Zähler und Nenner durch den ggT dividieren um zu Kürzen. Bisher muss ich wie gesagt niergendwo Dividieren. Wenn man 2 Ganzzahlen dividiert und die Ganzzahl-Division ohne Rest möglich ist: Darf man sich darauf verlassen, dass Flash eine Ganzzahl-Division mit absolute Genauigkeit durchführt? Oder kann man irgendwie eine Ganzzahl-Division erzwingen? Unter JAVA ist int/int = int. Unter AS ja leider nicht. 4.) Ob es nun Geld ist spielt ja keine so große Rolle. Aber es beschränkt sich in der Tat auf 2 Nachkommastellen. Ich habe mir mal erlaubt deinen Code in eine anständige Form zu bringen: Code: Number.prototype.fuenfer = function() {
var cent = Math.round(this*100); //int
var fivecents = Math.floor(cent/5); //int
var euro = fivecents / 20; //float
if (euro == int(euro)) { //keine nachkommastellen
return euro+".00";
}
else if (euro*10 == int(euro*10)) { //eine nachkommastelle
return euro+"0";
}
else {
return euro;
}
};
var a = 9.99999999999999999;
var b = 17.833;
var c = 99.977;
trace(a.fuenfer());
trace(b.fuenfer());
trace(c.fuenfer()); Aber ich muss ja einen Geldbetrag mit mehreren Faktoren multiplizieren bevor ich runden darf/muss. Da können ja schon Fehler passieren, die schwer vorherzusagen sind. |
| | |
| | #8 (permalink) |
| Techniker Registriert seit: Sep 2003 Ort: 64807
Beiträge: 16.321
|
"..in eine anständige Form zu bringen.." wusste nicht, das mein script unanständig ist ;-) "..Da können ja schon Fehler passieren, die schwer vorherzusagen sind.." ja sag mir bescheid, wenn's soweit ist.
__________________ die ultimative antwort auf alle programmierfragen: der debugger mfg h.g.seib www.SeibsProgrammLaden.de |
| | |
| | #9 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
3.) Ja, das darfst du. Zumindest solange du nicht immens grosse Zahlen benutzt. Am anderen Ende der Fahnenstange gibt es nämlich auch wieder Lücken. mfg. h.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (18-03-2006 um 23:57 Uhr) |
| | |
| | #10 (permalink) | |
| Neuer User Registriert seit: Sep 2001
Beiträge: 14
|
@hgseib hehe Das man so keinen code schreibt sollte jedem Entwickler klar sein: Code: return rnd == int(rnd) ? rnd+".00" : rnd*10 == int(rnd*10) ? rnd+"0" : rnd; Zitat:
@hazy fantazy Das ich ein Problem mit der Genauigkeit und nicht mit zu großen oder zu keinen Zahlen habe hatte ich ja schon geschrieben. -=Fazit=- Es scheint so zu sein, dass man die Genauigkeit nicht generell erhöhren kann. Es gibt einmal den Code von hgseib, der "etwas geschickter" rundet. Ob dadruch immer richtig gerechnet wird lässt sich schwer beweisen. ein Gegenbeispiel: 9,995 würde fälschlicherweise auf 10 gerundet und nicht auf 9,95€. Strings zu benutzen würde es nötig machen +,-,* selbst zu implementieren. Da stellt sich die Frage wie performant das Ganze nachher noch bleibt. Bleibt die Idee mit Brüchen zu rechnen. a/b muss aber gekürzt werden, was Division nötig macht. Laut "hazy fantazy" rechnet Flash mt INTs genau. Also ist (a-(a%b))/b eine präzise Rechnung. Bleibt ein Rest von (a%b)/b. Spätestens am Ende muss zur Ausgabe dieser Bruch auf b = 10 gebracht werden. Wenn man dies einfach durch Division ausrechner besteht wieder die Gefahr der Ungenauigkeit. | |
| | |
| | #11 (permalink) | |
| Herr Brot Registriert seit: Dec 2002
Beiträge: 1.692
| Zitat:
![]() 9,995 gerundet auf 2 Nachkommastellen IST 10,00. Oder was für ne Rundung möchtest du da realisieren?
__________________ „Ich war geheilt, all right!“ | |
| | |
| | #14 (permalink) |
| Nagelneuer User Registriert seit: Dec 2005
Beiträge: 924
|
Es gibt nach meiner Erfahrung keine allgemein gültigen Regeln, wie man mit der Ungenauigkeit umgehen kann. Es ist sehr applikationsspezifisch, an welchen Stellen du rundest. Wenn du z.B. eine Liste von gerundeten Zahlen darstellst, die aufsummiert werden sollen, dann musst du dich entscheiden, ob du die Summe der aufgerundeten oder der originalen Zahlen aufsummierst. Die Genauigkeit würde es erfordern, die originalen Zahlen zu addieren. Der User wäre aber wahrscheinlich irritiert, wenn sein Taschenrechner für 1,50 ein anderes Ergebnis als dein Programm ausgibt. Deshalb bleibt einem eigentlich nur, von Fall zu Fall zu entscheiden, denn dieses Problem hast du ja immer sobald die Anzeige von der absoluten Genauigkeit abweicht. wg. zu grossen Zahlen Das Problem tritt auch dann auf, wenn du Bruchrechnung benutzt und zwischendurch nicht kürzt oder nicht kürzen kannst mfg. h.
__________________ The fact that you've got "Replica" written on the side of your gun and the fact that I've got "Desert Eagle written on the side of mine ... :D Geändert von hazy fantazy (19-03-2006 um 11:57 Uhr) |
| | |
| | #15 (permalink) |
| Techniker Registriert seit: Sep 2003 Ort: 64807
Beiträge: 16.321
|
"..Das man so keinen code schreibt sollte jedem Entwickler klar sein:.." das ist, mit verlaub, totaler blödsinn!!! diese syntax ist genauso wie if.. while.. switch.. usw. voll korrekt. oder habe ich da etwas verpasst? hat bush die 'achse des bösen' neu definiert? wer x ? true : false; benützt muss mit einem überfall der amis rechnen? wer lesen kann, der kann lesen. wer es nicht kann, der kann halt nicht lesen. wer programmieren kann, der kann das verstehen. wer nicht programmieren kann, der kann auch die aufgeblasenen 300 zeilen nicht verstehen - oder etwas dazulernen. bliebe bestenfalls noch eine erklärende zeile. da es hier NUR um dieses problem geht ist die nicht notwendig. und hier ist auch nicht die 'krabbel-ecke', dass man jede erklärung bei 'adam und eva' anfangen muss. dann poste bei den einsteigern. bzw. ich muss ja nicht alles verraten ;-) 'Es ist immer "soweit".' und leider albern. welche antwort erwartest du auf so eine allerweltsfrage? das, wenn man aus einer zahl 3000mal die 975ste wurzel zieht, 17+4 addiert, noch 10000mal logaritmiert und daraus sinus berechnet, die rundungsfehler das endergebnis merklich verändern? darüber brauchen wir hier nicht zu diskutieren. benenne einen konkreten fall, dann kann man sich gedanken darüber machen, ob sich dabei die rundungsfehler der zahlendarstellung merklich auswirken können. 'Meine Frage bezog sich ja urspünglich auf eine generelle Erhöhung der Genauigkeit' darauf hasst du ursprünglich von mir lösungsansätze erhalten, die dir offensichtlich zu viel arbeit beinhalten? "9,995 würde fälschlicherweise auf 10 gerundet und nicht auf 9,95€." dann musst du nur definieren, ab wann du hoch bzw. runter runden willst. der computer kann das nicht riechen. bzw. mein script war nur eine anregung, ein bisschen eigeninitiative anstatt immer nur 'get nicht' zu sagen, ware auch mal ganz nett ;-) Code: Number.prototype.preisstaffel = function(runden_auf, abrunden) {
var fc = abrunden ? Math.floor : Math.ceil;
if (!runden_auf) return fc(this);
var s = -(int(Math.log(runden_auf)/Math.LN10));
do {
var n = Math.pow(10, ++s);
var r = runden_auf*n;
} while (int(r) != r);
// faktor m bestimmt, ab wann vorgerundet wird: beispiel b und c
var m = n*1000;
var rnd = fc(Math.round(this*n*m)/r/m)*r;
if (s<0) return rnd/n;
rnd = String(rnd).substr(0, -s)+"."+String(rnd).substr(-s);
return rnd.split("-.").join("-0.");
};
var a = 9.99999999999999999;
var b = 9.999999995;
var c = 9.99999995;
var d = -0.8368;
var e = 9999.977;
var f = 12345678;
var g = 901.44339;
trace(a+" => "+a.preisstaffel(.05, true));
trace(b+" => "+b.preisstaffel(.05, true));
trace(c+" => "+c.preisstaffel(.05, true));
trace(d+" => "+d.preisstaffel(.005, true));
trace(e+" => "+e.preisstaffel(.5, true));
trace(f+" => "+f.preisstaffel(2000, false));
trace(g+" => "+g.preisstaffel(0, false));
trace(g+" => "+g.preisstaffel(.125, true));
__________________ die ultimative antwort auf alle programmierfragen: der debugger mfg h.g.seib www.SeibsProgrammLaden.de Geändert von hgseib (19-03-2006 um 22:25 Uhr) |
| | |
![]() |
| Lesezeichen |
| Themen-Optionen | |
| Ansicht | |
| |