AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Guter Algorithmus zum multiplizieren großer Zahlen gesucht
Thema durchsuchen
Ansicht
Themen-Optionen

Guter Algorithmus zum multiplizieren großer Zahlen gesucht

Ein Thema von FAlter · begonnen am 15. Nov 2008 · letzter Beitrag vom 18. Nov 2008
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von FAlter
FAlter

Registriert seit: 21. Jul 2004
Ort: Ostfildern
1.096 Beiträge
 
FreePascal / Lazarus
 
#1

Guter Algorithmus zum multiplizieren großer Zahlen gesucht

  Alt 15. Nov 2008, 02:09
Hallo,

ich bin gerade dabei, darüber nachzudenken, wie ich am gescheitesten zwei 128 Bit große Integerzahlen auf meinem 32 Bit System multiplizieren kann.

Ein Gedanke wäre, die schriftliche Multiplikation aus der Grundschule nachzubilden und die Vorzeichen vorher extra behandeln/hinterher entsprechend wieder korrigieren, sodass man immer positive Zahlen multipliziert. Dabei würde ich 32bittig multiplizieren und die Ergebnisse dann entsprechend addieren.

Nun kommt mir dieser Ansatz aber sehr komplex vor. Gibt es vielleicht einen besseren Ansatz (einfacher, schneller?)

Ein noch schlimmerer und schon längst wieder verworfener Gedanke war es, das ganze so oft mit sich zu addieren wie es der andere Faktor angibt. Aber das ist zu umständlich und wird wohl ewig dauern.

Ideen können z. B. in Worten, Delphi (class operator Multiply(const Left, Right: Int128): Int128 oder Assembler (eax zeigt auf/adressiert Ergebnis, edx auf linken und ecx auf rechten Faktor) formuliert werden.
Int128 ist ein Record, dass zwei Int64 (Lo und Hi) enthält. Addition und Subtraktion, Vergleiche und Negation sind per Operatorüberladung bereits problemlos möglich.

So, jetzt schlaf ich erstmal ne Nacht darüber...

Mfg
FAlter
Felix Alter
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.219 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 02:17
Zitat:
ich bin gerade dabei, darüber nachzudenken, wie ich am gescheitesten zwei 128 Bit große Integerzahlen auf meinem 32 Bit System multiplizieren kann.
Weiter habe ich nicht gelesen. Aber das reicht schon.

Mein Tipp: Schlafen und morgen weiterdenken
Das werde ich jetzt auch tun.

Gute Nacht
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
Benutzerbild von Corpsman
Corpsman

Registriert seit: 8. Nov 2005
Ort: nähe Stuttgart
981 Beiträge
 
Delphi XE2 Professional
 
#3

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 09:33
Ich denke die Variante mit dem Zerlegen in die 4 Int32bit zahlen dürfte das beste sein.

so werden die ja schlieslich intern auch gerechnet ...

Die Schulmethode Shift add wird da wohl zu langsam sein .
Uwe
My Sitewww.Corpsman.de

My marble madness clone Balanced ( ca. 70,0 mb ) aktuell ver 2.01
  Mit Zitat antworten Zitat
Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#4

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 09:52
Also ich würde sagen, du kannst die Zahlen einfach ausmultiplizieren

Soll heißen, wenn du die in 2 64bit Zahlen splittest (verschnkt übrigens ein bit, da du 2 Vorzeichenbits hast)

Und dann kannnst du rechnen: A*B = a1*b1*2^128 + a1*b2*2^64 + a2*b1*2^64 + a2*b2

Jetzt musst du nur noch eine Funktion schreiben, die 2 64bit Zahlen multipliziert und das Ergebnis als 128bit Zahl zurückgibt (die 2^64 kannste ja shiften...)

(Mit 32bit wirds natürlich entsprechend länger ...)

Btw.: Auf fast allen modernen CPUs gibt es doch bereits vorgefertigte 128bit Arithmetik, oder nicht?
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

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

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 10:22
Die 64-Bit-Operationen sind aber auch nicht grad schnell (wenn man nicht grad in 64 Bit programmiert)
Dann doch lieber direkt 32 Bit-Operationen(?)

ups, stümmt, da gab's doch noch was (ok, dann halt weiter in ASM und SSE2)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von FAlter
FAlter

Registriert seit: 21. Jul 2004
Ort: Ostfildern
1.096 Beiträge
 
FreePascal / Lazarus
 
#6

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 10:22
Hi,

Zitat von jfheins:
Btw.: Auf fast allen modernen CPUs gibt es doch bereits vorgefertigte 128bit Arithmetik, oder nicht?
Und das wäre? Meine kann MMX, SSE und SSE2. Aber das sind alles Themen mit denen ich mich noch nie beschäftigt habe. Nur mal schnell nachgesehen, was das für Anweisungen kennt.

Die MMX-Register sind nur 64 Bit groß. Das ist defginitiv keine 128er Arithmetik. Außerdem, so weit ich es lese, arbeitet das maximal mit 32 bit, und man verarbeitet eben 2 32bittige Zahlen zusammen. Also ohne dass sich der Übertrag der einen z. B. auf die andere auswirkt.

Bei SSE lese ich nur was von Floating Point Operationen, auch da eben mehrere Zahlen glecihzeitig.

Bei SSE2 ist beides möglich, Packed Floats und Packed Integers; und da kann man schonmal endlich mit 64-Bit-Werten rechnen, von denen zwei in dem 128-Bit-Register stehen.

Ich sehe also keine direkte Möglichkeit mit meiner CPU 128-Bittig zu multiplizieren.

Mfg
FAlter
Felix Alter
  Mit Zitat antworten Zitat
Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#7

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 11:07
Naja, kann sein dass es das nicht in einem Befehl gibt ... ich hab nur SSE&128bit Register gelesen

Aber du brauchst ja auch nur 64bit Arithmetik

Denn: A*B = a1*b1*2^128 + a1*b2*2^64 + a2*b1*2^64 + a2*b2

Den ersten Term kannst du vergessen. (Würde deinen 128bit Typen sprengen)

Den 2. kannste ausrechnen mit 64bit und zum dritten dazuaddieren *wuppdi* haste den "hohen-ergbnis-64bit-wert" und der vierte Term liefert dir den niedrigen 64bit wert.

Also keine native 128bit Miltiplikation von Ganzzahlen aber alles was du brauchst um es mit wenigen Assemble Befehlen zu schreiben
  Mit Zitat antworten Zitat
Benutzerbild von FAlter
FAlter

Registriert seit: 21. Jul 2004
Ort: Ostfildern
1.096 Beiträge
 
FreePascal / Lazarus
 
#8

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 11:19
Hi,

aber wie sieht es mit den Überträgen aus, die bei der 64Bit-Multiplikation ggf. entstehen? Ich habe das Gefühl, diese werden wohl verworfen... [edit] Unsinniger Satz... [/edit]

Aber mit den 64 Bit (Quad Words):

http://flatassembler.net/docs.php?article=manual#2.1.16
SSE2 mit ghepackten QWords:
paddq performs the addition of packed quad words, psubq performs the substraction of packed quad words, pmuludq performs an unsigned multiply of low double words from each corresponding quad words and returns the results in packed quad words. These instructions follow the same rules for operands as the general MMX operations described in 2.1.14.


Das heißt die einzige 64-Bit-Multiplikation die es mit SSE2 gibt ist eine 32-Bit-Multiplikation mit 63 64-Bit ergebnissen, ansonsten kann man nur 64-Bit addieren und subtrahieren. Und zwar bei allen drei Anweisungen jeweils zwei Operationen (zwei Zahlen) gleichzeitig.

Also geht das mit der 64-Bit-Multiplikation auch nur über den 32-Bit-Umweg. Da werde ich wohl letztlich es doch per Hand mit 32-Bit stricken. Erstmal ohne SSE und dann wenns klappt und ich auch ne Division (mit Rest!) habe ggf. nochmal zum lernen / als Übung mit SSE.

Mfg
FAlter

[edit] Was mach ich denn alles für Fehler? Ich will meine Rechtschreibprüfung zurück haben! [/edit]
Felix Alter
  Mit Zitat antworten Zitat
Benutzerbild von FAlter
FAlter

Registriert seit: 21. Jul 2004
Ort: Ostfildern
1.096 Beiträge
 
FreePascal / Lazarus
 
#9

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 17:38
Hi,

hier mein aktueller Stand, ich habe in Assembler eine Proc zum unsigned multiplizieren geschrieben, die sogar ein 256 bittiges Ergebnis zurückliefert. Und dann In Delphi die Behandlung des Vorzeichens. Also jeweils in der Sprache, wo ich es einfacher fand.

Hier die Unsigned Multiplikation, ist sicherlich noch optimierungsfähig:
Delphi-Quellcode:
procedure MulPInt128U256U(const Result: PInt128; Left, Right: PInt128);
//Result: 256 bit --> zwei PInt128 (Lo, Hi) nacheinander!!!
//Unsigned!
//for 32-bit; nur wenn ss = ds, was bei Delphi immer zu sein scheint
//(kleine Optimierung durch Voraussetzung)
var
  buf1, buf2, buf3: array[0..4] of LongWord;
asm
//mul performs an unsigned multiplication of the operand and the accumulator.
//[...] If the operand is a double word, the processor multiplies it
//by the contents of EAX and returns the 64-bit result in EDX and EAX. mul
//sets CF and OF when the upper half of the result is nonzero, otherwise they
//are cleared. Rules for the operand are the same as for the inc instruction.

  push ebx
  push esi

  push eax
  push ecx

  mov esi, edx

  mov ecx, [ecx]
  mov ebx, eax
  call @@multiply

  mov ebx, [esp] //=original ecx
  mov ecx, [ebx+4]
  lea ebx, [buf1]
  call @@multiply

  mov ebx, [esp]
  mov ecx, [ebx+8]
  lea ebx, [buf2]
  call @@multiply

  mov ebx, [esp]
  mov ecx, [ebx+12]
  lea ebx, [buf3]
  call @@multiply

  //pop ecx
  add esp, 4 //Wert von ecx nicht wichtig, add schneller
  pop eax

  lea ebx, [buf1]
  xor ecx, ecx
  call @@add

  lea ebx, [buf2]
  call @@add

  lea ebx, [buf3]
  call @@add

  jmp @@end

  @@multiply:
    //eine Zeile multiplizieren
    //ecx = dword-faktor
    //abx = buf für ergebnis
    //und esi: Zeigt auf 128-Bit-Faktor!!!

    mov eax, [esi]
    mul ecx
    mov [ebx], eax
    mov [ebx+4], edx

    mov eax, [esi+4]
    mul ecx
    add[ebx+4], eax
    adc edx, 0
    mov [ebx+8], edx
    jc @@m1 //Übertrag speichern
      mov [ebx+12], 0
      jmp @@m2
    @@m1:
      mov [ebx+12], 1
    @@m2:

    mov eax, [esi+8]
    mul ecx
    add [ebx+8], eax
    adc [ebx+12], edx
    jc @@m3 //Übertrag speichern
      mov [ebx+16], 0
      jmp @@m4
    @@m3:
      mov [ebx+16], 1
    @@m4:

    mov eax, [esi+12]
    mul ecx
    add [ebx+12], eax
    adc [ebx+16], edx

  //Wenn jetzt noch ein Bit Übertrag ist, scheiss ich drauf!
  //Oder quäle mich wenn es immer total falsch rechnet :(
  //Meiner Berechnung sollten die 160 Bit (5*32 Bit) aber genau passen für eine
  //Multiplikation 32-Bit mit 128-Bit
  ret

  @@addcarry:
    //eax --> Ergebnis-Stelle
    //ebx ist wieder buf --> Stelle
    //ecx - letzter Übertrag

    add ecx, [ebx] //Übertrag verrechnen

    jnc @@a1 //neuer Übertrag?
      mov edx, 1 //Speichern
    jmp @@a2
    @@a1: //kein neuer Übertrag
      xor edx, edx //Speichern
    @@a2:

    add [eax], ecx //eigentliche Addition

    jnc @@a3 //neuer Übertrag?
      inc edx //Speichern/erhöhen
    @@a3:

    mov ecx, edx
  ret

  @@add:
    //EAX -> Ergebnis, letzte Stelle
    //(nicht sie Stelle, die zuerst addiert werden soll, sondern DAVOR)
    //zwei der Zeilen zusammenaddieren
    //ebx ist wieder buf
    //ecx - letzter Übertrag

    add eax, 4 //ne Stelle weiterrutschen

    push eax //4 Stellen addieren...
      call @@addcarry

      add eax, 4
      add ebx, 4
      call @@addcarry

      add eax, 4
      add ebx, 4
      call @@addcarry

      add eax, 4
      add ebx, 4
      call @@addcarry
    pop eax
  ret

  @@end:

  pop esi
  pop ebx
end;
Und hier die Vorzeichenbehaftete Multiplikation, die darauf zurückgreift:
Delphi-Quellcode:
procedure MulPInt128(const Result: PInt128; Left, Right: PInt128);
var
  Negative: Boolean;
  Help1, Help2: PInt128;
  UseH1, UseH2: Boolean;
  Reslt{$IFOPT Q+}, Reslt2{$ENDIF}: PInt128;
begin
  Help1 := nil; UseH1 := false;
  Help2 := nil; UseH2 := false;

  Negative := false;

  try

    if Left^ < 0 then
    begin
      Negative := true;
      UseH1 := true;
      New(Help1);
      Help1^ := -Left^;
    end
    else
      Help1 := Left;
    if Right^ < 0 then
    begin
      Negative := not Negative;
      UseH2 := true;
      New(Help2);
      Help2^ := -Right^;
    end
    else
      Help2 := Right;

    GetMem(Reslt, SizeOf(Int128) * 2);
    try
      MulPInt128U256U(Reslt, Help1, Help2);

      Result^ := Reslt^;

      {$IFOPT Q+}
      Reslt2 := Reslt;
      inc(Reslt2);

      if (Reslt2^ <> 0) or (Reslt < 0) then
        raise EIntOverflow.Create('Integer Overflow.');
      {$ENDIF}
    finally
      FreeMem(Reslt);
    end;

    if Negative then
      Result^ := -Result^;
  finally
    if UseH2 then Dispose(Help2);
    if UseH1 then Dispose(Help1);
  end;
end;
Mfg
FAlter
Felix Alter
  Mit Zitat antworten Zitat
Benutzerbild von jfheins
jfheins

Registriert seit: 10. Jun 2004
Ort: Garching (TUM)
4.579 Beiträge
 
#10

Re: Guter Algorithmus zum multiplizieren großer Zahlen gesuc

  Alt 15. Nov 2008, 18:02
Ich kenne mich jetzt nicht mit Assembler aus, aber ... du addierst doch nicht etwa, oder?

Außerdem kann ich mir nicht vorstellen, dass das effizient ist - das sieht mir einfach zu lang aus

Um nochmal auf meinen Vorschlag zurückzukommen:

128bit - A*B = a1*b2*2^64 + a2*b1*2^64 + a2*b2

Kannst du weiter runterbrechen - d.h. eine Multiplikation von 2 64bit Werten sieht dann so aus:

x*y = x1*y1*2^64 + x1*y2*2^32 + x2*y1*2^32 + x2*y2

Wobei x1 das high-order dword ist und x2 das low-order dword. [s]Außerdem kannst du wieder den ersten Term vernachlässigen (würde wieder zu einem Überlauf führen)[s] Vergiss das ^^

Du musst dann eben Funktionen für 64bit und 32bit Multiplikation sowie zur Multiplikation mit 2er Potenzen zur Verfügung stellen

Du könntest daraus auch etwas rekursives machen nach dem Motto "Teile und Herrsche"
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 17:19 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