Recent

Author Topic: Karatsuba algorithm for polynomial multiplication  (Read 5278 times)

delphius

  • Jr. Member
  • **
  • Posts: 79
Re: Karatsuba algorithm for polynomial multiplication
« Reply #15 on: October 23, 2024, 10:08:04 pm »
Well, let's try to count?  ::)
Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. uses
  4.   Math;
  5.  
  6. type
  7.   TPolynomial = class
  8.   private
  9.     FCoeff: array of Double;
  10.     procedure SetCoeff(Index: Integer; Value: Double);
  11.     function GetCoeff(Index: Integer): Double;
  12.     function GetDegree: Integer;
  13.   public
  14.     constructor Create(Degree: Integer);
  15.     constructor CreateFromArray(const CoeffArray: array of Double);
  16.     function Add(const B: TPolynomial): TPolynomial;
  17.     function Subtract(const B: TPolynomial): TPolynomial;
  18.     function Multiply(const B: TPolynomial): TPolynomial;
  19.     function Equals(const B: TPolynomial): Boolean; reintroduce;
  20.     function Evaluate(X: Double): Double;
  21.     function LowerPart(D: Integer): TPolynomial;
  22.     function UpperPart(D: Integer): TPolynomial;
  23.     function Shift(D: Integer): TPolynomial;
  24.     procedure WritePoly(VarChar: Char = 'x');
  25.     property Coeff[Index: Integer]: Double read GetCoeff write SetCoeff;
  26.     property Degree: Integer read GetDegree;
  27.   end;
  28.  
  29. constructor TPolynomial.Create(Degree: Integer);
  30. begin
  31.    if Degree < 0 then
  32.     Degree := 0;
  33.   SetLength(FCoeff, Degree + 1);
  34. end;
  35.  
  36. constructor TPolynomial.CreateFromArray(const CoeffArray: array of Double);
  37. var
  38.   I: Integer;
  39. begin
  40.   SetLength(FCoeff, Length(CoeffArray));
  41.   for I := 0 to High(CoeffArray) do
  42.     FCoeff[I] := CoeffArray[I];
  43. end;
  44.  
  45. function TPolynomial.GetCoeff(Index: Integer): Double;
  46. begin
  47.   Result := FCoeff[Index];
  48. end;
  49.  
  50. procedure TPolynomial.SetCoeff(Index: Integer; Value: Double);
  51. begin
  52.   FCoeff[Index] := Value;
  53. end;
  54.  
  55. function TPolynomial.GetDegree: Integer;
  56. begin
  57.   Result := High(FCoeff);
  58. end;
  59.  
  60. function TPolynomial.Add(const B: TPolynomial): TPolynomial;
  61. var
  62.   MaxDegree, I: Integer;
  63. begin
  64.   MaxDegree := Max(Self.Degree, B.Degree);
  65.   Result := TPolynomial.Create(MaxDegree);
  66.   for I := 0 to MaxDegree do
  67.     Result.Coeff[I] := Self.Coeff[I] + B.Coeff[I];
  68. end;
  69.  
  70. function TPolynomial.Subtract(const B: TPolynomial): TPolynomial;
  71. var
  72.   MaxDegree, I: Integer;
  73. begin
  74.   MaxDegree := Max(Self.Degree, B.Degree);
  75.   Result := TPolynomial.Create(MaxDegree);
  76.   for I := 0 to MaxDegree do
  77.     Result.Coeff[I] := Self.Coeff[I] - B.Coeff[I];
  78. end;
  79.  
  80. function TPolynomial.Multiply(const B: TPolynomial): TPolynomial;
  81. var
  82.   ResultDegree, I, J: Integer;
  83. begin
  84.   ResultDegree := Self.Degree + B.Degree;
  85.   Result := TPolynomial.Create(ResultDegree);
  86.   for I := 0 to Self.Degree do
  87.     for J := 0 to B.Degree do
  88.       Result.Coeff[I + J] := Result.Coeff[I + J] + (Self.Coeff[I] * B.Coeff[J]);
  89. end;
  90.  
  91. function TPolynomial.Equals(const B: TPolynomial): Boolean;
  92. var
  93.   I: Integer;
  94. begin
  95.   if Self.Degree <> B.Degree then
  96.     Exit(False);
  97.    
  98.   for I := 0 to Self.Degree do
  99.   begin
  100.     if Self.Coeff[I] <> B.Coeff[I] then
  101.       Exit(False);
  102.   end;
  103.   Result := True;
  104. end;
  105.  
  106. function TPolynomial.Evaluate(X: Double): Double;
  107. var
  108.   I: Integer;
  109. begin
  110.   Result := 0;
  111.   for I := Self.Degree downto 0 do
  112.     Result := Result * X + Self.Coeff[I];
  113. end;
  114.  
  115. function TPolynomial.LowerPart(D: Integer): TPolynomial;
  116. var
  117.   I: Integer;
  118. begin
  119.   Result := TPolynomial.Create(D - 1);
  120.   for I := 0 to D - 1 do
  121.     Result.Coeff[I] := Self.Coeff[I];
  122. end;
  123.  
  124. function TPolynomial.UpperPart(D: Integer): TPolynomial;
  125. var
  126.   I: Integer;
  127. begin
  128.   Result := TPolynomial.Create(Self.Degree - D);
  129.   for I := 0 to Self.Degree - D do
  130.     Result.Coeff[I] := Self.Coeff[I + D];
  131. end;
  132.  
  133. function TPolynomial.Shift(D: Integer): TPolynomial;
  134. var
  135.   I: Integer;
  136. begin
  137.   Result := TPolynomial.Create(Self.Degree + D);
  138.   for I := 0 to Self.Degree do
  139.     Result.Coeff[I + D] := Self.Coeff[I];
  140. end;
  141.  
  142. procedure TPolynomial.WritePoly(VarChar: Char = 'x');
  143. var
  144.   I: Integer;
  145. begin
  146.   for I := 0 to Degree do
  147.     Write(FCoeff[I]:0:2, VarChar, '^', I, ' ');
  148.   WriteLn;
  149. end;
  150.  
  151. function Karatsuba(const f, g: TPolynomial): TPolynomial;
  152. var
  153.   temp1, temp2, h1, h2, h3, h: TPolynomial;
  154.   d: Integer;
  155. begin
  156.   // Базовый случай: если один из многочленов равен нулю
  157.   if (f.Degree = 0) and (f.Coeff[0] = 0) or
  158.      (g.Degree = 0) and (g.Coeff[0] = 0) then
  159.   begin
  160.     Result := TPolynomial.Create(0);
  161.     Result.Coeff[0] := 0;
  162.     Exit;
  163.   end;
  164.  
  165.   // Базовый случай: оба многочлена - константы
  166.   if (f.Degree = 0) and (g.Degree = 0) then
  167.   begin
  168.     Result := TPolynomial.Create(0);
  169.     Result.Coeff[0] := f.Coeff[0] * g.Coeff[0];
  170.     Exit;
  171.   end;
  172.  
  173.   // Получаем максимальную степень и вычисляем d
  174.   d := Ceil(Max(f.Degree, g.Degree) / 2);
  175.  
  176.   // Разделяем многочлены на нижнюю и верхнюю части
  177.   temp1 := f.LowerPart(d);
  178.   temp2 := g.LowerPart(d);
  179.   h1 := Karatsuba(temp1, temp2);  // flow * glow
  180.  
  181.   temp1 := f.UpperPart(d);
  182.   temp2 := g.UpperPart(d);
  183.   h2 := Karatsuba(temp1, temp2);  // fup * gup
  184.  
  185.   // Вычисляем (flow + fup) * (glow + gup)
  186.   temp1 := f.LowerPart(d).Add(f.UpperPart(d)); // flow + fup
  187.   temp2 := g.LowerPart(d).Add(g.UpperPart(d)); // glow + gup
  188.   h3 := Karatsuba(temp1, temp2);
  189.  
  190.  
  191.   // Объединяем результаты
  192.   temp1 := h3.Subtract(h1).Subtract(h2);
  193.   temp2 := temp1.Shift(d);
  194.   h := h1.Add(temp2);
  195.   temp2 := h2.Shift(2 * d);
  196.   Result := h.Add(temp2);
  197. end;
  198.  
  199. procedure TestKaratsuba;
  200. var
  201.   a, b, c: TPolynomial;
  202. begin
  203.   a := TPolynomial.CreateFromArray([9, 7, 4, 8, 9]);
  204.   b := TPolynomial.CreateFromArray([8, 4, 2, 1, 6, 5, 9, 4]);
  205.  
  206.   WriteLn('Polynomial a:');
  207.   a.WritePoly('x');
  208.   WriteLn('Polynomial b:');
  209.   b.WritePoly('x');
  210.  
  211.   c := Karatsuba(a, b);
  212.  
  213.   WriteLn('Result of Karatsuba multiplication (c):');
  214.   c.WritePoly('x');
  215. end;
  216.  
  217. procedure RunTests;
  218. var
  219.   a, b, c: TPolynomial;
  220. begin
  221.   a := TPolynomial.CreateFromArray([1]);
  222.   b := TPolynomial.CreateFromArray([1]);
  223.   c := Karatsuba(a, b);
  224.   Assert(c.Equals(TPolynomial.CreateFromArray([1])), 'Test 1 Failed');
  225.  
  226.   a := TPolynomial.CreateFromArray([2]);
  227.   b := TPolynomial.CreateFromArray([3]);
  228.   c := Karatsuba(a, b);
  229.   Assert(c.Equals(TPolynomial.CreateFromArray([6])), 'Test 2 Failed');
  230.  
  231.   a := TPolynomial.CreateFromArray([1, 1]); // x + 1
  232.   b := TPolynomial.CreateFromArray([2, 1]); // x + 2
  233.   c := Karatsuba(a, b);
  234.   Assert(c.Equals(TPolynomial.CreateFromArray([2, 3, 1])), 'Test 3 Failed'); // 2 + 3x + 1x^2
  235.  
  236.   a := TPolynomial.CreateFromArray([1, 2, 3]); // 1 + 2x + 3x^2
  237.   b := TPolynomial.CreateFromArray([4, 5]); // 4 + 5x
  238.   c := Karatsuba(a, b);
  239.   Assert(c.Equals(TPolynomial.CreateFromArray([4, 13, 22, 15, 0])), 'Test 4 Failed'); // 4 + 13x + 22x^2 + 15x^3 + 0x^4
  240.   {
  241.   The result of multiplying two polynomials is calculated as follows:
  242.  
  243.   a(x) = 1 + 2x + 3x^2
  244.   b(x) = 4 + 5x
  245.  
  246.   The multiplication is done using the distributive property:
  247.  
  248.   1. Multiply 1 by (4 + 5x):
  249.      1 * (4 + 5x) = 4 + 5x
  250.  
  251.   2. Multiply 2x by (4 + 5x):
  252.      2x * (4 + 5x) = 8x + 10x^2
  253.  
  254.   3. Multiply 3x^2 by (4 + 5x):
  255.      3x^2 * (4 + 5x) = 12x^2 + 15x^3
  256.  
  257.   Combining these results gives us:
  258.   c(x) = (4 + 5x) + (8x + 10x^2) + (12x^2 + 15x^3)
  259.  
  260.   Now, summing the like terms:
  261.   - Constant: 4
  262.   - x terms: 5x + 8x = 13x
  263.   - x^2 terms: 10x^2 + 12x^2 = 22x^2
  264.   - x^3 terms: 15x^3
  265.  
  266.   Thus, the final result is:
  267.   c(x) = 4 + 13x + 22x^2 + 15x^3
  268.  
  269.   Note that the degree of the resulting polynomial can be equal to the sum of the degrees of the original polynomials:
  270.   Maximum degree of a(x) = 2
  271.   Maximum degree of b(x) = 1
  272.   Therefore, the maximum degree of c(x) can be 2 + 1 = 3.
  273.  
  274.   We include 0x^4 for completeness, so the final result can be represented as:
  275.   c = TPolynomial.CreateFromArray([4, 13, 22, 15, 0])
  276. }
  277.  
  278.   a := TPolynomial.CreateFromArray([0]); // 0
  279.   b := TPolynomial.CreateFromArray([2, 1]); // 2 + x
  280.   c := Karatsuba(a, b);
  281.   Assert(c.Equals(TPolynomial.CreateFromArray([0])), 'Test 5 Failed'); // 0
  282.  
  283.   WriteLn('All tests passed!');
  284. end;
  285.  
  286. begin
  287.   RunTests;
  288.   TestKaratsuba;
  289. end.
  290.  
fpmtls - ssl/tls 1.3 implementation in pure pascal
fpmailsend - sending a simple email message
pascal-webui - use web browser as gui and fpc as backend

tetrastes

  • Hero Member
  • *****
  • Posts: 694
Re: Karatsuba algorithm for polynomial multiplication
« Reply #16 on: October 23, 2024, 10:27:37 pm »
First compile your demo with debug data:

Code: Bash  [Select][+][-]
  1. > cd /the_directory_of_project/
  2. > fpc -ountitled -l -Mobjfpc -Sh -Fcutf8 -gl -O- -B untitled.pas

Then load the debugger, still in the directory of the project:
Code: Bash  [Select][+][-]
  1. > gdb untitled

Once gdb is loaded, press the "r" character (for run) + "enter"

You should get something like this:

Quote
(gdb) r
Starting program: /home/fred/Polynomial_test/untitled
Polynomial a
4
+9.000000000000*x^4+7.000000000000*x^3+4.000000000000*x^2+8.000000000000*x^1+9.0
00000000000*x^0
Polynomial b
7
+8.000000000000*x^7+4.000000000000*x^6+2.000000000000*x^5+1.000000000000*x^4+6.0
00000000000*x^3+5.000000000000*x^2+9.000000000000*x^1+4.000000000000*x^0
Polynomial c
11
+72.000000000000*x^11+92.000000000000*x^10+78.000000000000*x^9+103.000000000000*
x^8+173.000000000000*x^7+143.000000000000*x^6+166.000000000000*x^5+176.000000000
000*x^4+158.000000000000*x^3+133.000000000000*x^2+113.000000000000*x^1+36.000000
000000*x^0
[Inferior 1 (process 576738) exited normally]
(gdb)

Note that I did not get any error.

You have forgotten to add -Cr option. Then you would get:

Polynomial a
4
+9.000000000000*x^4+7.000000000000*x^3+4.000000000000*x^2+8.000000000000*x^1+9.000000000000*x^0
Polynomial b
7
+8.000000000000*x^7+4.000000000000*x^6+2.000000000000*x^5+1.000000000000*x^4+6.000000000000*x^3+5.000000000000*x^2+9.000000000000*x^1+4.000000000000*x^0
An unhandled exception occurred at $0000000100001D30:
ERangeError: Range check error
  $0000000100001D30  KARATSUBA,  line 39 of project1.lpr
  $00000001000020A1  KARATSUBA,  line 55 of project1.lpr
  $0000000100002CF9  main,  line 129 of project1.lpr
  $0000000100002E66
  $0000000100011240
  $00000001000016F4
  $00007FF9E3707374
  $00007FF9E3D3CC91

tetrastes

  • Hero Member
  • *****
  • Posts: 694
Re: Karatsuba algorithm for polynomial multiplication
« Reply #17 on: October 23, 2024, 10:32:35 pm »
How big do you think integer is?

I would advice using a type that is not dependent on platform, like longint
🤣

There is no difference in using 16 or 32-bit integers in this code.

Fred vS

  • Hero Member
  • *****
  • Posts: 3716
    • StrumPract is the musicians best friend
Re: Karatsuba algorithm for polynomial multiplication
« Reply #18 on: October 23, 2024, 10:35:28 pm »
You have forgotten to add -Cr option.
Ooops, indeed, thanks to note it (and for the tip  ;) )
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

tetrastes

  • Hero Member
  • *****
  • Posts: 694
Re: Karatsuba algorithm for polynomial multiplication
« Reply #19 on: October 23, 2024, 10:40:00 pm »
Well, let's try to count?  ::)

Compile your code with Range checking (-Cr) and you'll get:

An unhandled exception occurred at $0000000100001A3C:
ERangeError: Range check error
  $0000000100001A3C  GETCOEFF,  line 47 of test.lpr
  $0000000100001BAE  ADD,  line 67 of test.lpr
  $000000010000236E  KARATSUBA,  line 194 of test.lpr
  $00000001000026F0  RUNTESTS,  line 233 of test.lpr
  $0000000100002843  main,  line 287 of test.lpr
  $0000000100002866
  $000000010000F8A0
  $00000001000016F4
  $00007FF9E3707374
  $00007FF9E3D3CC91

user07022024

  • New Member
  • *
  • Posts: 14
Re: Karatsuba algorithm for polynomial multiplication
« Reply #20 on: October 23, 2024, 10:57:38 pm »
@tetrastes changing logical condition force us to redefine base case

Maybe choosing min(d-1,f.deg)
as degree of temporary polynomial will help


@delphius That would be my next question rewrite this polynomial unit to the generic class
but I would like to test Karatsuba multiplication first
« Last Edit: October 23, 2024, 11:01:35 pm by user07022024 »

MathMan

  • Sr. Member
  • ****
  • Posts: 434
Re: Karatsuba algorithm for polynomial multiplication
« Reply #21 on: October 23, 2024, 11:24:03 pm »
@user07022024

That is what I said initially. The degree of the polynomial is d, but the number of elements in the array representing the polinomial is d+1! The split has to consider the number of elements.

These two - degree and number of elements - are not correctly distinguished in your implementation and you end up accessing the factor array out of bounds.

You also try to implement Karatsuba for polynomials with different degrees, which makes it much more complex than it needs to be (and less efficient too). Start simple and implement it for polinomials with equal degree. After that we can design a generic multiplication on top of that.

tetrastes

  • Hero Member
  • *****
  • Posts: 694
Re: Karatsuba algorithm for polynomial multiplication
« Reply #22 on: October 23, 2024, 11:46:15 pm »
One more note.

Code: Pascal  [Select][+][-]
  1.    for k := 0 to f.deg - d do

How do you suppose it can work if f.deg<d (which can occur at the first step already, if f.deg much less then g.deg)?
I don't understand from your pseudocode what to do in this case. I would say that it is buggy.  :-X

user07022024

  • New Member
  • *
  • Posts: 14
Re: Karatsuba algorithm for polynomial multiplication
« Reply #23 on: October 24, 2024, 08:24:09 am »

Lets ignore my attempt of writing this function
and start writing this function from beginning but
 being as close as possible to this pseudocode which i found

Laksen

  • Hero Member
  • *****
  • Posts: 801
    • J-Software
Re: Karatsuba algorithm for polynomial multiplication
« Reply #24 on: October 24, 2024, 12:19:57 pm »
How big do you think integer is?

I would advice using a type that is not dependent on platform, like longint
🤣

There is no difference in using 16 or 32-bit integers in this code.

What if the input polynomial have more than 32767 coefficients?

tetrastes

  • Hero Member
  • *****
  • Posts: 694
Re: Karatsuba algorithm for polynomial multiplication
« Reply #25 on: October 24, 2024, 12:49:40 pm »
And what if more than 2 147 483 647?  :D
I mean that it has nothing to do with the issues of this code. Till now we test with 5 and 8.  ;)

user07022024

  • New Member
  • *
  • Posts: 14
Re: Karatsuba algorithm for polynomial multiplication
« Reply #26 on: October 26, 2024, 02:22:24 pm »

MathMan you know this algorithm can you write me what's wrong

I changed the code in such way that it controls range of array of coefficients
and I don't see errors at this moment but it returns wrong result


Code: Pascal  [Select][+][-]
  1. function Karatsuba(f,g:TPolynomial):TPolynomial;
  2. var temp1,temp2:TPolynomial;
  3.     h,h1,h2,h3:TPolynomial;
  4.     k,m,n,d:integer;
  5. begin
  6.  //Base case f = 0 or g = 0
  7.   if ((f.deg = 0)and(f.coeff[0] = 0)) or ((g.deg = 0)and(g.coeff[0] = 0)) then
  8.   begin
  9.     h := makePolynomial(0);
  10.     h.coeff[0] := 0;
  11.     Karatsuba := h;
  12.     Exit
  13.   end;
  14.   //Base case both polynomials are constant
  15.   if ((f.deg = 0) and (g.deg = 0)) then
  16.   begin
  17.     h := makePolynomial(0);
  18.     h.coeff[0] := f.coeff[0] * g.coeff[0];
  19.     Karatsuba := h;
  20.     Exit
  21.   end;
  22.   begin
  23.   //Checking which polynomial has maximum degree
  24.     d := max(f.deg,g.deg);
  25.     //Calculating ceiling of half of max degree  
  26.     d := (d + 1) div 2;
  27.     //Creating temporary polynomial which stores lower part of polynomial f
  28.     m := 1 + min(d - 1,f.deg);
  29.     temp1 := makePolynomial(m-1);
  30.     for k := 0 to m - 1 do
  31.       temp1.coeff[k] := f.coeff[k];
  32.      //Creating temporary polynomial which stores lower part of polynomial g
  33.      n := 1 + min(d - 1,g.deg);
  34.     temp2 := makePolynomial(n-1);
  35.     for k := 0 to n - 1 do
  36.        temp2.coeff[k] := g.coeff[k];
  37.     //Recursive call of function Karatsuba to calculate product flow * glow
  38.     h1 := Karatsuba(temp1,temp2);
  39.     //Creating temporary polynomial which stores upper part of polynomial f
  40.     temp1 := makePolynomial(ord(f.deg - m >= 0)*(f.deg - m));
  41.     temp1.coeff[0] := 0;
  42.     for k := 0 to f.deg - m do
  43.        temp1.coeff[k] := f.coeff[k + m];
  44.     //Creating temporary polynomial which stores upper part of polynomial g
  45.     temp2 := makePolynomial(ord(g.deg - n >= 0)*(g.deg - n));
  46.     temp2.coeff[0] := 0;
  47.     for k := 0 to g.deg - n do
  48.        temp2.coeff[k] := g.coeff[k+n];
  49.     //Recursive call of function Karatsuba to calculate product fup * gup  
  50.     h2 := Karatsuba(temp1,temp2);
  51.     //Creating temporary polynomial to store lower part of polynomial g
  52.     temp1 := makePolynomial(n-1);
  53.     //Creating temporary polynomial to store upper part of polynomial g
  54.     temp2 := makePolynomial(ord(g.deg - n >= 0)*(g.deg - n));
  55.     for k := 0 to n - 1 do
  56.        temp1.coeff[k] := g.coeff[k];
  57.     temp2.coeff[0] := 0;
  58.     for k := 0 to g.deg - n do
  59.        temp2.coeff[k] := g.coeff[k+n];
  60.     //Creating polynomial glow + gup
  61.     h3 := AddPolynomials(temp1,temp2);
  62.     //Set coefficients of temporary polynomial to coefficients of lower part of polynomial f
  63.     for k := 0 to m - 1 do
  64.        temp1.coeff[k] := f.coeff[k];
  65.     //Creating temporary polynomial which stores upper part of polynomial f  
  66.     temp2 := makePolynomial(ord(f.deg - m >= 0)*(f.deg - m));
  67.     temp2.coeff[0] := 0;
  68.     for k := 0 to f.deg - m do
  69.        temp2.coeff[k] := f.coeff[k+m];
  70.     //Creating polynomial flow + fup  
  71.     temp1 := AddPolynomials(temp1,temp2);
  72.     //Recursive call of function Karatsuba to calculate product (flow + fup)*(glow + gup)
  73.     h3 := Karatsuba(temp1,h3);
  74.     //Merging results , calculation middle terms
  75.     temp1 := SubtractPolynomials(h3,h1);
  76.     temp1 := SubtractPolynomials(temp1,h2);
  77.     temp2 := makePolynomial(temp1.deg+d);
  78.     for k := 0 to temp1.deg do
  79.        temp2.coeff[k + d] := temp1.coeff[k];
  80.     for k := 0 to d - 1 do
  81.        temp2.coeff[k] := 0;
  82.     //Adding lower part and middle part
  83.     h := AddPolynomials(h1,temp2);
  84.     //Creating upper part
  85.     temp2 := makePolynomial(h2.deg + 2*d);
  86.     for k := 0 to h2.deg do
  87.         temp2.coeff[k + 2*d] := h2.coeff[k];
  88.     for k := 0 to 2*d - 1 do
  89.         temp2.coeff[k] := 0;
  90.     //Adding upper part to current result
  91.     h := AddPolynomials(h,temp2);
  92.     Karatsuba := h;
  93.   end;
  94. end;
  95.  


And here is what gdb prints


Code: Text  [Select][+][-]
  1. Starting program: F:\Karatsuba/testKaratsuba
  2. [New Thread 8896.0x4424]
  3. [New Thread 8896.0x35e4]
  4. [New Thread 8896.0x15e0]
  5. [New Thread 8896.0x15ec]
  6. Polynomial a
  7. 4
  8. +9.000000000000*x^4+7.000000000000*x^3+4.000000000000*x^2+8.000000000000*x^1+9.000000000000*x^0
  9. Polynomial b
  10. 7
  11. +8.000000000000*x^7+4.000000000000*x^6+2.000000000000*x^5+1.000000000000*x^4+6.000000000000*x^3+5.000000000000*x^2+9.000000000000*x^1+4.000000000000*x^0
  12. Polynomial c
  13. 12
  14. +20.000000000000*x^12+82.000000000000*x^11+92.000000000000*x^10+78.000000000000*x^9+83.000000000000*x^8+163.000000000000*x^7+143.000000000000*x^6+166.000000000000*x^5+176.000000000000*x^4+158.000000000000*x^3+133.000000000000*x^2+113.000000000000*x^1+36.000000000000*x^0
  15. [Inferior 1 (process 8896) exited normally]
  16.  







MathMan

  • Sr. Member
  • ****
  • Posts: 434
Re: Karatsuba algorithm for polynomial multiplication
« Reply #27 on: October 26, 2024, 06:33:08 pm »
@user07022024

I'll take a look - will respond later today, or tomorrow latest.

Cheers,
MathMan

MathMan

  • Sr. Member
  • ****
  • Posts: 434
Re: Karatsuba algorithm for polynomial multiplication
« Reply #28 on: October 27, 2024, 06:47:15 pm »
@user07022024

...
I'll take a look - will respond later today, or tomorrow latest.
...

As promised here is my feedback. I spent a lot of time trying to debug your code. However, you made it a lot more complex then it needs to be with many corner cases, creation of many intermediate, shuffling data back & forth between polynomes, etc. All said, I couldn't get your version fixed simply. So I did what I initially wanted to avoid, as this smells a bit like homework ...

Code: Pascal  [Select][+][-]
  1. function Karatsuba(
  2.  f: TPolynomial;
  3.  g: TPolynomial
  4. ):TPolynomial;
  5.  
  6. var
  7.   Count: NativeInt; // generic loop control
  8.   Split: NativeInt; // degree of polynome split
  9.  
  10.   pl: tPolynomial;  // larger degree polynomial
  11.   ps: tPolynomial;  // smaller degree polynomial
  12.  
  13.   plHi, plLo: tPolynomial; // high & low part of larger polynome
  14.   psHi, psLo: tPolynomial; // same for smaller polynome
  15.  
  16.   pHi, pMid, pLo: tPolynomial; // partial results of Karatsuba
  17.  
  18. begin
  19.   Result := MakePolynomial( f.Deg+g.Deg );
  20.  
  21.   // base case:
  22.   // - both polinomes are constant
  23.   // - the polynome product is the product of constants
  24.   if( ( f.Deg=0 ) and ( g.Deg=0 ) ) then begin
  25.     Result.Coeff[ 0 ] := f.Coeff[ 0 ] * g.Coeff[ 0 ];
  26.     Exit;
  27.   end;
  28.  
  29.   // sort the polynomes by degree to simplify the following calculations
  30.   if( f.Deg>=g.Deg ) then begin
  31.     pl := f;
  32.     ps := g;
  33.   end else begin
  34.     pl := g;
  35.     ps := f;
  36.   end;
  37.  
  38.   // get the split degree
  39.   Split := pl.Deg div 2;
  40.  
  41.   // now split the polynomials into high & low parts
  42.   // the split of the larger polynome is trivial, as high & low part exist
  43.   plLo := MakePolynomial( Split );
  44.   for Count := 0 to Split do plLo.Coeff[ Count ] := pl.Coeff[ Count ];
  45.   plHi := MakePolynomial( pl.Deg-Split-1 );
  46.   for Count := Split+1 to pl.Deg do plHi.Coeff[ Count-Split-1 ] := pl.Coeff[ Count ];
  47.  
  48.   // for the smaller polynome we have to check, if the high part exists
  49.   psLo := MakePolynomial( Min( Split, ps.Deg ) );
  50.   for Count := 0 to Min( Split, ps.Deg ) do psLo.Coeff[ Count ] := ps.Coeff[ Count ];
  51.   if( Split>=ps.Deg ) then begin
  52.     psHi := MakePolynomial( 0 );
  53.     psHi.Coeff[ 0 ] := 0;
  54.   end else begin
  55.     psHi := MakePolynomial( ps.Deg-Split-1 );
  56.     for Count := Split+1 to ps.Deg do psHi.Coeff[ Count-Split-1 ] := ps.Coeff[ Count ];
  57.   end;
  58.  
  59.   // calculate low & high product
  60.   pLo := Karatsuba( plLo, psLo );
  61.   pHi := Karatsuba( plHi, psHi );
  62.  
  63.   // calculate middle product ( plHi+plLo )*( psHi+psLo )
  64.   // we can re-use low parts for the sums
  65.   plLo := AddPolynomials( plLo, plHi );
  66.   psLo := AddPolynomials( psLo, psHi );
  67.   pMid := Karatsuba( plLo, psLo );
  68.  
  69.   // finally sum all parts up, positionally correct
  70.   for Count := 0 to pLo.Deg do
  71.     Result.Coeff[ Count ] := pLo.Coeff[ Count ];
  72.   for Count := 0 to pHi.Deg do
  73.     Result.Coeff[ Result.Deg-pHi.Deg+Count ] := pHi.Coeff[ Count ];
  74.   for Count := 0 to pMid.Deg do
  75.     Result.Coeff[ Count+Split+1 ] := Result.Coeff[ Count+Split+1 ] + pMid.Coeff[ Count ];
  76.   for Count := 0 to pLo.Deg do
  77.     Result.Coeff[ Count+Split+1 ] := Result.Coeff[ Count+Split+1 ] - pLo.Coeff[ Count ];
  78.   for Count := 0 to pHi.Deg do
  79.     Result.Coeff[ Count+Split+1 ] := Result.Coeff[ Count+Split+1 ] - pHi.Coeff[ Count ];
  80. end;
  81.  

It follows the outline you gave in your first post. But be aware that it still includes the shortcomings I mentioned

- using floating point for the factors will lead to rounding/overflow errors, once you work with polinomes of large degree or with large factors
- it is not efficient, as it recurses fully down to constant polinomes. Already in your example a lot of redundant calculations (multiplication by constant 0.0) take place

Cheers,
MathMan
« Last Edit: October 27, 2024, 07:19:12 pm by MathMan »

user07022024

  • New Member
  • *
  • Posts: 14
Re: Karatsuba algorithm for polynomial multiplication
« Reply #29 on: October 27, 2024, 10:10:20 pm »

My school age passed away nearly quarter century ago
so it is not a homework

I found this pseudocode on youtube and tried to follow it or at least stay as close as possible to it

 

TinyPortal © 2005-2018