Autor Beitrag
BOZ_er
Hält's aus hier
Beiträge: 1



BeitragVerfasst: Do 21.04.05 17:50 
Hallo,

ich versuche seit geraumer Zeit Polynommultiplikation mittels FFT zu implementieren.
Hintergrund ist der, daß ich große Integerwerte miteinander multiplizieren möchte.
Soweit so gut, die FFT und die inverse FFT habe ich aus dem FFTW Projekt genommen (die stellen eine dll zur Verfügung). Es geht auch alles soweit nur mache ich irgendwas noch grundlegen falsch - ich weis nur nicht was.

Das resultiert dadrinn, daß einige Polynome korrekt multipliziert werden - andere hingegen nur Schwachsin ergeben.

Die Multiplikation funktioniert bei mir jetzt so:
- Integerzahlen werden als Polynome interpretiert
- die zwei Polynome der Faktoren werden mit einer FFT konvertiert
- die beiden komplexen Polynome punktweise multipliziert
- das Ergebnis mit IFFT zurückkonvertiert und jede Stelle durch die Anzahl der Stellenzahl dividiert.

Die DLL gibts hier : ftp.fftw.org/pub/fft...tw-3.0.1-w32-pl1.zip

Mein code sieht zZ so aus:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
function fftwf_plan_dft_r2c_1d(n : Integer; inData : PSingle; outData : PSingle; flags : Longword) : Pointer; cdeclexternal 'fftw3.dll';
function fftwf_plan_dft_c2r_1d(n : Integer; inData : PSingle; outData : PSingle; flags : Longword) : Pointer; cdeclexternal 'fftw3.dll';
procedure fftwf_destroy_plan(plan : Pointer); cdeclexternal 'fftw3.dll';
procedure fftwf_execute(plan : Pointer); cdeclexternal 'fftw3.dll';


procedure TForm1.Button1Click(Sender: TObject);
Type
 complex = record
  real, imag: single;
 end;
Var
 FFT,FFT2, IFFT: Pointer;
 x,y: array of single;
 w,v,u: array of complex;
 N, I: Integer;
begin
 N := 8;
 SetLength(x, N);
 SetLength(y, N);
 SetLength(w, N div 2+1); //diese Länge des Ergebnisses ist im FFTW Manual so zu finden
 SetLength(v, N div 2+1);
 SetLength(u, N div 2+1);

 FFT := fftwf_plan_dft_r2c_1d(8, @x[0], @w[0],64); //Aufrufkonvention des FFTW Pakets....
 FFT2 := fftwf_plan_dft_r2c_1d(8, @y[0], @v[0],64);
 IFFT := fftwf_plan_dft_c2r_1d(8, @u[0], @x[0],64);

 x[0] := 0//das sind die beiden Array mit den reellen Polynomen X[0] ist 10^0, X[1] 10^1 usw...
 x[1] := 0;
 x[2] := 0;
 x[3] := 0;
 x[4] := 0;
 x[5] := 0;
 x[6] := 0;
 x[7] := 0;

 y[0] := 0;
 y[1] := 0;
 y[2] := 0;
 y[3] := 0;
 y[4] := 0;
 y[5] := 0;
 y[6] := 0;
 y[7] := 0;


 fftwf_execute(FFT); //auf beide arrays den FFT anwenden
 fftwf_execute(FFT2);

 for i:=0 to (n div 2do begin
   u[i].real:=v[i].real*w[i].real-v[i].imag*w[i].imag; //Ergebnis im Komplexen stellenweise multiplizieren
   u[i].imag:=v[i].imag*w[i].real-v[i].real*w[i].imag;
 end;

 fftwf_execute(IFFT);

 for I := 0 to N-1 do x[I] := x[I] / N; //Ergebnis durch Anzahl der Stellen teilen
 for I := 0 to N-1 do Memo2.Lines.Add(FloatToStr(x[I]));  //und mir ausgeben

 fftwf_destroy_plan(FFT);
 fftwf_destroy_plan(FFT2);
 fftwf_destroy_plan(IFFT);
end;


Es geht alles gut solange in den Arrays nur kleine Ziffern sind (zB 00100000 in beiden).
Dann ist das Ergebnis korrekterweise (00001000).
Er gibt totalen Mist aus wenn ich zB (66000000) quadrieren möchte.


Weis irgendwer was ich dabei grundlegend falsch mache??

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt.
Moderiert von user profile iconChristian S.: Topic aus CLX / Delphi Language (Object-Pascal) verschoben am Do 21.04.2005 um 17:53
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 24.04.05 00:55 
Ich glaube es liegt an der Periodizität des Phasen- und des Frequenzraumes. (Der Frequenzraum ist periodisch, weil der Phasenraum diskret gesampelt wurde, und der Phasenraum ist periodisch, weil das Spektrum des Signals dann auch nur an diskreten Stellen gegeben ist; deswegen ist das rekonstruierte Signal jetzt auch periodisch.)

Wenn die DFT einen endlichendimensionalen Vektor liefert, ist dieser theoretisch unendlich lange periodisch fortgesetzt zu verstehen. Das heisst, es geht auf beide Seiten (negative und positive Frequenzen) bis unendlich. Es ist nicht so, dass z.B. die negativen und hohen Frequenzen einfach Null sind.

Das hat zur Folge, dass, wenn du ein Vektor mit einem anderen "über den Rand" faltest, geht die Information nicht etwa verloren, sondern kommt am anderen Ende wieder rein. Das merkt man zum Beispiel auch bei Convolution-Filter (z.B. Hall) bei Audiosignalen. Wenn man am Ende eines Liedes nicht zuerst mit Nullen paddet, hört man den Schlusshall des Liedes noch kurz am Anfang (angenommen, man faltet das gesamte Lied mit der Impulsresponse, was man ja aber eigentlich nicht tut ;))

Hier, was ich meine an einem Beispiel:
[1,2,3,4,5][1,0,0,0,0] = [1,2,3,4,5]
[1,2,3,4,5][0,1,0,0,0] = [5,1,2,3,4]
[1,2,3,4,5][0,0,1,0,0] = [4,5,1,2,3]

(★ = Faltungsoperator)

Ich nehme an, dass dir genau dieser Effekt Probleme bereitet. Danach riecht es hier zu mindest.

Ausserdem ist zu beachten, dass Überläufe (beim schriftlichen rechnen "behalte Eins") natürlich nicht nicht direkt der höheren Stelle dazuaddiert wird.
Sagen wir mal, dass du 123*123 rechnen willst (im Dezimalsystem). Also:
[1,2,3, 0,0,0][1,2,3, 0,0,0] = [9,12,10,4,1,0]
Wie du siehst sind im Resultat auch Zahlen grössergleich 10 möglich. Das Resultat der Rechnung ist dann:
         9 *1
  +    12  *10
  +   10   *100
  +   4    *1000
  +  1     *10000
  + 0      *100000
  ----------------
     15129

// Edit:
Deine Multiplikation in C ist falsch: (a+i*b)*(c+i*d)=(ac-bd)+i(ad+bc). Ich seh bei dir zwei mal ein Minus, das kann nicht sein. ;)