AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Code-Bibliothek Library: Algorithmen Delphi Delphi's LargeWord-Divisionsfehler beheben
Thema durchsuchen
Ansicht
Themen-Optionen

Delphi's LargeWord-Divisionsfehler beheben

Ein Thema von himitsu · begonnen am 9. Sep 2005
Antwort Antwort
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#1

Delphi's LargeWord-Divisionsfehler beheben

  Alt 9. Sep 2005, 17:52
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

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:
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);
Lösen kann man dieses Problem dadurch, dass man sich nicht auf den Compiler verläßt und selbst die entspechenden Funktionen aufruft.


Und hier hätten wir mal die beiden Funktionen ^^
Delphi-Quellcode:
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;
Aufrufen kann man diese z.B. auf folgende Weise:
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.
$2B or not $2B
  Mit Zitat antworten Zitat
Antwort Antwort

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz