program fmpq_series;
{$mode objfpc}{$H+}
{$packrecords C}
uses
gmp, ctypes, SysUtils;
{ ===== GMP / FLINT type definitions ===== }
type
mp_limb_t = ptruint;
mp_limb_signed_t = ptruint;
slong = mp_limb_signed_t;
fmpz = mp_limb_signed_t;
Pfmpz = ^fmpz;
fmpz_t = array[0..0] of fmpz;
Pfmpz_t = ^fmpz_t;
fmpq = record
num : fmpz;
den : fmpz;
end;
Pfmpq = ^fmpq;
fmpq_t = fmpq;
Pfmpq_t = ^fmpq_t;
fmpq_poly_struct = record
coeffs : Pfmpz;
den : fmpz_t;
alloc : clong;
length : slong;
end;
Pfmpq_poly_struct = ^fmpq_poly_struct;
fmpq_poly_t = fmpq_poly_struct;
Pfmpq_poly_t = ^fmpq_poly_t;
{ Minimal FILE type placeholder for stdout passing }
PFILE = Pointer;
{ ===== External FLINT declarations ===== }
procedure _fmpz_clear_mpz(f: fmpz); cdecl; external 'flint';
procedure fmpq_poly_init(poly: Pfmpq_poly_struct); cdecl; external 'flint';
function fmpq_poly_set_str(poly: Pfmpq_poly_struct; str: PChar): clong; cdecl; external 'flint';
procedure fmpq_poly_revert_series_newton(res: Pfmpq_poly_struct; poly: Pfmpq_poly_struct; n: mp_limb_signed_t); cdecl; external 'flint';
function fmpq_poly_fprint_pretty(f: PFILE; poly: Pfmpq_poly_struct; varname: PChar): clong; cdecl; external 'flint';
function fmpq_poly_get_str(poly: Pfmpq_poly_struct): PChar; cdecl; external 'flint';
function fmpq_poly_get_str_pretty(poly: Pfmpq_poly_struct; varname: PChar): PChar; cdecl; external 'flint';
procedure fmpq_poly_set_coeff_fmpq(poly: Pfmpq_poly_struct; n: mp_limb_signed_t; x: Pfmpq); cdecl; external 'flint';
procedure fmpq_poly_clear(poly: Pfmpq_poly_struct); cdecl; external 'flint';
procedure fmpq_set_si(res: Pfmpq; p: mp_limb_signed_t; q: mp_limb_t); cdecl; external 'flint';
procedure fmpz_set_si(f: Pfmpz; val: mp_limb_signed_t); cdecl; external 'flint';
procedure fmpz_fac_ui(f: Pfmpz; n: mp_limb_t); cdecl; external 'flint';
procedure fmpq_set_fmpz_frac(res: Pfmpq; p: Pfmpz; q: Pfmpz); cdecl; external 'flint';
{ ===== Inline helpers (mirrors FreeBasic inline subs) ===== }
procedure fmpz_init(f: Pfmpz); inline;
begin
f^ := 0;
end;
procedure fmpz_clear(f: Pfmpz); inline;
begin
{ If the top bit pattern signals an MPZ pointer, call the real clear }
if (f^ shr (32 - 2)) = 1 then
_fmpz_clear_mpz(f^);
end;
procedure fmpq_init(x: Pfmpq); inline;
begin
x^.num := 0;
x^.den := 1;
end;
procedure fmpq_clear(x: Pfmpq); inline;
begin
fmpz_clear(@x^.num);
fmpz_clear(@x^.den);
end;
{ FreePascal does not expose a raw FILE* stdout directly in the same way.
We declare it from libc instead. }
//var
//libc_stdout: PFILE; external 'c' name 'stdout';
//StdOut: Text;
{ ===== Main program ===== }
var
i, sone : slong;
series : fmpq_poly_t;
rseries : fmpq_poly_t;
term : fmpq_t;
mpz_num : fmpz;
mpz_den : fmpz;
size : Integer;
sp : PChar;
begin
WriteLn('starting');
size := 28;
fmpz_init(@mpz_num);
fmpz_init(@mpz_den);
fmpq_init(@term);
fmpq_poly_init(@series);
fmpq_poly_init(@rseries);
{ ---- arctan series via string ---- }
WriteLn('assign the arctan series to series');
WriteLn('fmpq_poly_set_str(@series, "10 0 1 0 -1/3 0 1/5 0 -1/7 0 1/9")');
fmpq_poly_set_str(@series, '10 0 1 0 -1/3 0 1/5 0 -1/7 0 1/9');
WriteLn;
WriteLn('now get the series back into a string');
WriteLn('sp=fmpq_poly_get_str(@series)');
WriteLn;
sp := fmpq_poly_get_str(@series);
WriteLn('--> ', sp);
WriteLn;
WriteLn('get a pretty reprentation into string');
WriteLn('sp=fmpq_poly_get_str_pretty(@series, "x")');
WriteLn;
sp := fmpq_poly_get_str_pretty(@series, 'x');
WriteLn('--> ', sp);
WriteLn;
WriteLn('now reverse the series to get the tangent series');
WriteLn('fmpq_poly_revert_series_newton(@rseries, @series , 10)');
WriteLn;
fmpq_poly_revert_series_newton(@rseries, @series, 10);
WriteLn('print the series');
WriteLn('fmpq_poly_fprint_pretty(stdout, @rseries, "x")');
WriteLn;
Write('--> ');
//fmpq_poly_fprint_pretty(@stdout, @rseries, 'x');
sp := fmpq_poly_get_str_pretty(@rseries, 'x');
WriteLn('rseries--> ', sp);
WriteLn;
WriteLn('==========================================');
WriteLn;
{ ---- sine series via loop ---- }
WriteLn('populate series with the sine series');
WriteLn('x - x^3/3! + x^5/5! ... using a program block');
WriteLn('and then reverse the series');
WriteLn;
Write('--> ');
sone := 1;
i := 1;
while i < size do
begin
fmpz_set_si(@mpz_num, sone);
fmpz_fac_ui(@mpz_den, mp_limb_t(i));
fmpq_set_fmpz_frac(@term, @mpz_num, @mpz_den);
fmpq_poly_set_coeff_fmpq(@series, i, @term);
Inc(i);
fmpq_set_si(@term, 0, 1); { even power terms are 0 }
fmpq_poly_set_coeff_fmpq(@series, i, @term);
Inc(i);
sone := -sone;
end;
fmpq_poly_revert_series_newton(@rseries, @series, size);
sp := fmpq_poly_get_str_pretty(@series, 'x');
WriteLn('rseries--> ', sp);
WriteLn;
WriteLn;
{ ---- arctan series via loop ---- }
WriteLn('do the same with the arctan series');
WriteLn('x - x^3/3 + x^5/5 ...');
WriteLn;
Write('--> ');
sone := 1;
i := 1;
while i < size do
begin
fmpq_set_si(@term, sone, mp_limb_t(i));
fmpq_poly_set_coeff_fmpq(@series, i, @term);
Inc(i);
fmpq_set_si(@term, 0, 1); { even power terms are 0 }
fmpq_poly_set_coeff_fmpq(@series, i, @term);
Inc(i);
sone := -sone;
end;
fmpq_poly_revert_series_newton(@rseries, @series, size);
sp := fmpq_poly_get_str_pretty(@rseries, 'x');
WriteLn('rseries--> ', sp);
WriteLn;
{ ---- cleanup ---- }
fmpq_clear(@term);
fmpq_poly_clear(@series);
fmpq_poly_clear(@rseries);
fmpz_clear(@mpz_den);
fmpz_clear(@mpz_num);
end.