| Autor |
Beitrag |
meiners
Hält's aus hier
Beiträge: 3
Windows XP, Linux
Delphi 6
|
Verfasst: Mi 22.09.04 17:33
Hallo.
in meiner Anwendung gibt es einen Codebereich, in dem eine hohe Anzahl von Multiplikationen zweier Integer-Zahlen stattfindet, die jeweils einen Zahlenbereich von 0 bis ca. 1.000.000 aufweisen können. Der folgenden Codeabschnitt illustriert das Problem:
X: Double;
I, J: Integer;
...
X:= I*J;
...
X enthält den beabsichtigten Wert, wenn der Productwert <= (2^31)-1 ist. Wird das Produkt größer, wird X unbeabsichtigt aber korrekt negativ, da der Compiler (Delphi 6) eine 32-Bit-Integer-Multiplikation generiert.
Beabsichtigt ist eigentlich, dass der Compiler Code generiert, der die Integerzahlen vorher in Double konvertiert und erst dann multipliziert. Etwa so:
X:= Double(I)*J;
Allerdings verweigert der Compiler die Übersetzung, da Double kein Aufzählungstyp (ordinal type) ist. Eine mögliche Lösung ist:
X:= 1.*I*J;
Das erzwingt eine automatische Typumwandlung in Double, erzeugt allerdings auch eine zusätzliche und überflüssige Multiplikation mit 1.
Kennt irgendjemand eine Methode um diese überflüssige Multiplikation mit 1. zu vermeiden. Das beste wäre, wenn der Compiler (oder das Laufzeitsystem) ein "Integer-to-Double" Typumwandlung in der Art wie die oben automatisch vollzogene durchzuführt. Aber weder Compiler noch Laufzeitsystem scheinen einen solchen Mechanismus anzubieten. Auch im internet (unterstützt durch google) bin ich nicht fündig geworden. Ich kann mir nicht vorstellen, dass bisher niemand Ärger mit solchen numerischen Problemen in Delphi gehabt hat. Mir scheint es gibt da eine Lösung, die ich aber einfach nicht sehe. Kann mir jemand helfen?
Mit freundlichem Gruß
Hans Meiners
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Mi 22.09.04 17:43
Was spricht dagegen, den Integer vorher in einen Double zu kopieren? Im Prozessor muss der Integer auch erst in ein Floatingpointregister geladen werden. Man müsste halt mal testen, was am schnellsten ist. Vielleicht könntest du aber auch 64-Bit-Integer verwenden?
Gruß,
Jörg
_________________ Die Antworten auf die 5 häufigsten Fragen:
1. Copy(), Pos(), Length() --- 2. DoubleBuffered:=True; --- 3. Application.ProcessMessages bzw. TThread --- 4. ShellExecute() --- 5. Keine Vergleiche von Real-Typen mit "="!
|
|
MartinPb
      
Beiträge: 698
|
Verfasst: Mi 22.09.04 17:51
Zuerst eine Frage: warum willst du, daß der Compiler vorher die Integer in Double konvertiert? Ich sehe keine Nachteile darin, daß I * J als Integer multipliziert werden. Ein Problem würde ich eher darin sehen, daß es nicht als Integer multipliziert. Integer sind schneller.
Ich weiß nicht an welcher Stelle die automatische Konvertierung anfängt, aber es würde mich nicht wundern, wenn es bereits vorher wäre. X ist Double und deshalb ist es keine Integerberechnung. Es ist eine Doubleberechnung die Integerzahlen akzeptiert. Aber auch wenn der Compiler da ein Mix macht, was ich nicht glaube, wo ist das Problem? Ich schätze der Grund wieso keiner bisher da eine Lösung anbietet ist der, daß es da keine Probleme gibt.
_________________ Gruß
Martin
|
|
meiners 
Hält's aus hier
Beiträge: 3
Windows XP, Linux
Delphi 6
|
Verfasst: Mi 22.09.04 19:01
Hallo Martin,
| MartinPb hat folgendes geschrieben: | | ... Ich sehe keine Nachteile darin, daß I * J als Integer multipliziert werden. Ein Problem würde ich eher darin sehen, daß es nicht als Integer multipliziert. Integer sind schneller. |
Das Problem dabei ist, das der Code dann nur für Produktwerte funktioniert, die kleiner als (2^31)-1 sind. Wenn etwa I=50.000 und J=60.000 ist, dann ist I*J=3Mrd.? Die ist als Integer aber nicht darstellbar. Das dahinterliegende Bitmuster wird von der Integer-Arithmetic des Prozessors als negative 32-bit-Integer-Zahl angesehen. Bei Verwendung des Datentyps Cardinal wäre die Zahl noch darstellbar. Aber wenn dann I=70.000 wird kommt es auch bei Cardinal zum Überlauf.
| MartinPb hat folgendes geschrieben: | | Ich weiß nicht an welcher Stelle die automatische Konvertierung anfängt, aber es würde mich nicht wundern, wenn es bereits vorher wäre. X ist Double und deshalb ist es keine Integerberechnung. Es ist eine Doubleberechnung die Integerzahlen akzeptiert. Aber auch wenn der Compiler da ein Mix macht, was ich nicht glaube, wo ist das Problem? Ich schätze der Grund wieso keiner bisher da eine Lösung anbietet ist der, daß es da keine Probleme gibt. |
Der Compiler hat keine Veranlassung auf der rechten Seite mit Gleitkomma-Multiplikationen zu arbeiten. Dort befinden sich nur Integer-Typen. Er erzeugt den Typumwandlungscode erst, wenn er das Produktergebnis in die Double-Variable X ablegen muss. Ich habe das mit einem kleinen Programm mit Delphi 6 ausprobiert. Der Compiler braucht einen Hinweis, das er bei der Multiplikation den Gleitkommaprozessor verwenden soll und nicht die Integer-Arithmetik. Das kann man z.B in C/C++ mit
X = (double)I*J
ohne Probleme hinkriegen.
Gruß
Hans
|
|
meiners 
Hält's aus hier
Beiträge: 3
Windows XP, Linux
Delphi 6
|
Verfasst: Mi 22.09.04 19:11
Hallo Jörg,
| .Chef hat folgendes geschrieben: | | Was spricht dagegen, den Integer vorher in einen Double zu kopieren? Im Prozessor muss der Integer auch erst in ein Floatingpointregister geladen werden. Man müsste halt mal testen, was am schnellsten ist. Vielleicht könntest du aber auch 64-Bit-Integer verwenden? |
Sicher könnte man zumindest eine der beiden Integer-Zahlen in einer Hilfsvariable vom Typ Double ablegen und dann die Hilfsvariable im Multiplikationsausdruck verwenden. Das Problem dabei ist: wenn der Codebereich in einer Schleife steckt und sehr oft ausgeführt wird (Größenordnung 10^9), versucht man jede überflüssige Aktion (insbsondere Zusatzmultiplikationen oder Speichervorgänge) zu vermeiden.
Gruß Hans
|
|
.Chef
      
Beiträge: 1112
|
Verfasst: Mi 22.09.04 19:13
Jup, deshalb meine Frage, obs nicht auch ein 64-Bit-Integer tut. Notfalls kann man das auch komplett in asm machen. Der Beweis bleibt dem werten Leser überlassen (vorerst ...). 
_________________ Die Antworten auf die 5 häufigsten Fragen:
1. Copy(), Pos(), Length() --- 2. DoubleBuffered:=True; --- 3. Application.ProcessMessages bzw. TThread --- 4. ShellExecute() --- 5. Keine Vergleiche von Real-Typen mit "="!
|
|
|