![]() |
Delphi's LargeWord-Divisionsfehler beheben
Leider scheint es im Delphi 'nen winzigen Fehler in den 64-Bit-Routinen zu geben.
Und zwar scheint der Compiler "immer" die Integer-Versionen (signed) zu verwenden, selbst wenn es sich um eine vorzeichenlose Variable (unsigned) handelt. Bei der Multiplikation, Subtaktion und den Binäroperationen (and, or, shl, shr ...) ist dieses zum Glück vernachlässigbar, solange die Overlow-Checks deaktiviert sind. Allerdings treten bei der Division (div) und Modul-Division (mod) nette Fehler auf, wenn mit Werten über 9.223.372.036.854.775.807 (>= $8000000000000000) gerechnet wird. Im Moment bin ich mir aber noch nicht zu 100% sicher, dass dieser Fehler wirklich in allen "neueren" Delphi-Compilern enthalten ist. Wobei D1 bis D5 auf jeden Fall Fehlerfrei ist, denn diese Versionen kennen ja noch keine Vorzeichenlosen 64-Bit Variablen, wenn sie über haupt schon mal was von 64-Bit gehört haben :zwinker: Also gibt es als Erstes mal die Testmöglichkeit. "Error - SIGNED division" sollte wohl bei den Meisten auftauchen. Wenn jemand "OK - unsigned division" sieht, so möge er/sie sich bitte melden. Und wer "Error - NO division result" erspäht, der sollte sich wirklich Sorgen machen -.-''
Delphi-Quellcode:
Lösen kann man dieses Problem dadurch, dass man sich nicht auf den Compiler verläßt und selbst die entspechenden Funktionen aufruft.
Var L: LargeWord;
L := LargeWord($8000000000000000); L := L div 10; If L = $0CCCCCCCCCCCCCCC Then MessageBox(0, 'OK - unsigned division', '', 0) Else If L = LargeWord($F333333333333334) Then MessageBox(0, 'Error - SIGNED division', '', 0) Else MessageBox(0, 'Error - NO division result', '', 0); Und hier hätten wir mal die beiden Funktionen ^^
Delphi-Quellcode:
Aufrufen kann man diese z.B. auf folgende Weise:
Procedure DivW64;
// unit System > __lludiv ASM PUSH EBP PUSH EDI PUSH ESI PUSH EBX MOV EBX, [ESP + 20] MOV ECX, [ESP + 24] OR ECX, ECX JNZ @Slow OR EDX, EDX JZ @Quick OR EBX, EBX JZ @Quick @Slow: MOV EBP, ECX MOV ECX, 64 XOR EDI, EDI XOR ESI, ESI @Loop: SHL EAX, 1 RCL EDX, 1 RCL ESI, 1 RCL EDI, 1 CMP EDI, EBP JB @noSub JA @Sub CMP ESI, EBX JB @noSub @Sub: SUB ESI, EBX SBB EDI, EBP INC EAX @noSub: LOOP @Loop JMP @Exit @Quick: DIV EBX XOR EDX, EDX @Exit: POP EBX POP ESI POP EDI POP EBP RET 8 End; Procedure ModW64; // unit System > __llumod ASM PUSH EBP PUSH EDI PUSH ESI PUSH EBX MOV EBX, [ESP + 20] MOV ECX, [ESP + 24] OR ECX, ECX jnz @Slow OR EDX, EDX JZ @Quick OR EBX, EBX JZ @Quick @Slow: MOV EBP, ECX MOV ECX, 64 XOR EDI, EDI XOR ESI, ESI @Loop: SHL EAX, 1 RCL EDX, 1 RCL ESI, 1 RCL EDI, 1 CMP EDI, EBP JB @noSub JA @Sub CMP ESI, EBX JB @noSub @Sub: SUB ESI, EBX SBB EDI, EBP INC EAX @noSub: LOOP @Loop MOV EAX, ESI MOV EDX, EDI JMP @Exit @Quick: DIV EBX XCHG EAX, EDX XOR EDX, EDX @Exit: POP EBX POP ESI POP EDI POP EBP RET 8 End;
Delphi-Quellcode:
Var XXX, YYY, ZZZ: LargeWord;
// ZZZ := XXX div YYY; ASM PUSH DWORD PTR [&YYY + 4] PUSH DWORD PTR [&YYY] MOV EAX, DWORD PTR [&XXX] MOV EDX, DWORD PTR [&XXX + 4] CALL DivW64 MOV DWORD PTR [&ZZZ], EAX MOV DWORD PTR [&ZZZ + 4], EDX End; // ZZZ := XXX mod YYY; ASM PUSH DWORD PTR [&YYY + 4] PUSH DWORD PTR [&YYY] MOV EAX, DWORD PTR [&XXX] MOV EDX, DWORD PTR [&XXX + 4] CALL ModW64 MOV DWORD PTR [&ZZZ], EAX MOV DWORD PTR [&ZZZ + 4], EDX End; Dieses wird einfach in den Pascal-Quelltext eingefügt. Der obrige Test würde dann also so aussehen.
Delphi-Quellcode:
Var L: LargeWord;
L := LargeWord($8000000000000000); ASM PUSH 0 PUSH 10 MOV EAX, DWORD PTR [&L] MOV EDX, DWORD PTR [&L + 4] CALL DivW64 MOV DWORD PTR [&L], EAX MOV DWORD PTR [&L + 4], EDX End; If L = $0CCCCCCCCCCCCCCC Then MessageBox(0, 'OK - unsigned division', '', 0) Else If L = LargeWord($F333333333333334) Then MessageBox(0, 'Error - SIGNED division', '', 0) Else MessageBox(0, 'Error - NO division result', '', 0); PS: mit diesen Funktionen könnte man auch in den Delphiversionen bis 5 das LargeWord integrieren, dazu bräuchte man ja nur diese Funktionen auf einen LargeInt/Int64 anzuwenden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:14 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz