00001 // polynomial arithmetic 00002 // last change: 2004-09-13 00003 00004 #ifndef POLYNOMIAL_HEADER_ 00005 #define POLYNOMIAL_HEADER_ 00006 00012 #include <gmp.h> 00013 00015 namespace polynomial 00016 { 00017 00018 //#define DEBUG /* for explicit DEBUGGING-sessions */ 00019 //#define VERBOSE /* be more verbose */ 00020 00021 // this define should be triggered by Makefile 00022 // #define USE_DFT /* enable use of discrete fourier transform */ 00023 #if !defined(USE_DFT) && (CONTINUATION_METHOD==2) 00024 #define USE_DFT /* enable use of discrete fourier transform */ 00025 #endif 00026 00027 typedef mpz_t* TPolynom; 00028 typedef const mpz_t* TconstPolynom; 00029 /* A polynomial is defined by an array of mpz_t-coefficients: 00030 P(x)=a0*x^0+a1*x^1+...+a[k-1]*x^[k-1], 00031 stored as (a0,a1,a2,...,a[k-1]). 00032 */ 00033 00034 /* Hints for function calls: 00035 00036 TPolynom denotes a pointer to an array of coefficients 00037 (which thereby defines a polynomial). 00038 00039 As usual in C++, take respect to the following calling conventions: 00040 00041 Parameter Restrictions/Properties 00042 ------------------------------------------------------------- 00043 mpz_t* p mutable pointer, mutable data 00044 const mpz_t* p mutable pointer, constant data 00045 mpz_t* const p constant pointer, mutable data 00046 const mpz_t* const p constant pointer, constant data 00047 00048 "const TPolynom P" and "TPolynom const P" are (unfortunately) equivalent. 00049 Both define a constant pointer to a mutable polynomial! 00050 00051 For this reason, I have defined an auxiliary datatype 00052 for constant polynomials: TconstPolynom 00053 So keep this in mind: 00054 00055 Parameter Restrictions/Properties 00056 ---------------------------------------------------------------- 00057 TPolynom P P mutable, coefficients mutable 00058 const TPolynom P P constant, coefficients mutable 00059 TPolynom const P P constant, coefficients mutable 00060 TconstPolynom P P mutable, coefficients constant 00061 const TconstPolynom P P constant, coefficients constant 00062 TconstPolynom const P P constant, coefficients constant 00063 00064 */ 00065 00066 00075 class TTempPolynom : private ForbidAssignment 00076 { 00077 private: 00078 mpz_t* const data; 00079 const int _capacity; 00080 public: 00081 explicit TTempPolynom(const int n) : data(new mpz_t[n]), _capacity(n) 00082 { 00083 //cout << "allocate polynomial of size " << n << endl; 00084 for (int i=0; i<n; ++i) mpz_init(data[i]); 00085 } 00086 TTempPolynom(const int n, const int estimated_operand_size) : data(new mpz_t[n]), _capacity(n) 00087 { 00088 //cout << "allocate polynomial of size " << n << endl; 00089 for (int i=0; i<n; ++i) mpz_init2(data[i],estimated_operand_size); 00090 } 00091 ~TTempPolynom() 00092 { 00093 //cout << "dispose polynomial of size " << _capacity << endl; 00094 for (int i=_capacity-1; i>=0; --i) mpz_clear(data[i]); 00095 delete [] data; 00096 } 00097 int capacity() const { return _capacity; } 00098 00099 //const mpz_t& operator[] (const unsigned int i) const { return data[i]; } 00100 //mpz_t& operator[] (const unsigned int i) { return data[i]; } 00101 00102 // dangerous, but helpful: 00103 // remember: TPolynom will not live longer than TempPolynom! 00104 operator TPolynom() const { return data; } 00105 }; 00106 00107 00114 void print (const TconstPolynom P, int k); 00115 00116 00128 void eval(mpz_t res, const TconstPolynom P, const int k, const mpz_t x, const mpz_t m); 00129 // berechnet mit dem Hornerschema res = P(x) mod m 00130 00131 00132 #ifdef USE_DFT 00133 // fast discrete fourier transformation 00134 // (will allocate internal temporary memory, which you may want to release) 00135 00142 void clear_dft_tempmemory() ; 00143 00144 #endif 00145 00146 00161 int classic_mul(const TPolynom Pr, const int kr, 00162 const TconstPolynom P1, const int k1, 00163 const TconstPolynom P2, const int k2); 00164 // Pres = P1*P2, &Pres must be different from &P1,&P2 00165 // returns degree of the resulting polynomial 00166 // complexity: O(k1*k2) 00167 // (classical method, implemented alternatively to Karatsuba for small polynomials) 00168 00169 00185 int classic_mul(const TPolynom Pr, const int kr, 00186 const TconstPolynom P1, const int k1, 00187 const TconstPolynom P2, const int k2, const mpz_t m); 00188 // Pres = P1*P2, &Pres must be different from &P1,&P2 00189 // returns degree of the resulting polynomial 00190 // complexity: O(k1*k2) 00191 // (classical method, implemented alternatively to Karatsuba for small polynomials) 00192 00193 00194 00207 int square(const TPolynom R, const int kR, const TconstPolynom P, const int k, const mpz_t m); 00208 // R = P^2, &R must be different from &P 00209 // returns degree of resulting polynomial 00210 // complexity: O(k^1.59) -> Karatsuba 00211 00212 00224 int square(const TPolynom R, const int kR, const TconstPolynom P, const int k); 00225 // R = P^2, &R must be different from &P 00226 // returns degree of resulting polynomial 00227 // complexity: O(k^1.59) -> Karatsuba 00228 00229 00246 int mul(const TPolynom R, const int kR, 00247 TconstPolynom P1, int k1, 00248 TconstPolynom P2, int k2, const mpz_t m); 00249 // Pres = P1*P2, &R must be different from &P1,&P2 00250 // returns degree of the resulting polynomial 00251 // complexity: O(max(k1,k2)^1.59) -> Karatsuba 00252 // resp. complexity: O((k1+k2)*ld(k1+k2)) -> using (optimal) dft 00253 00254 00269 int mul(const TPolynom R, const int kR, 00270 TconstPolynom P1, int k1, 00271 TconstPolynom P2, int k2); 00272 // Pres = P1*P2, &R must be different from &P1,&P2 00273 // returns degree of resulting polynomial 00274 // complexity: O(max(k1,k2)^1.59) -> Karatsuba 00275 00276 00288 void reciprocal(TPolynom R, int &kR, const TconstPolynom P, const int k, const mpz_t m, const unsigned int scale=0); 00289 // computes the reciprocal polynomial of P, 00290 // R must provide enough memory! 00291 // the given polynomial will be scaled using x^scale as multiplier, 00292 // thereby shifting the coefficients by scale places 00293 00294 00312 void classic_div(TPolynom Q, int &kQ, TPolynom R, int &kR, 00313 const TconstPolynom P1, int k1, 00314 const TconstPolynom P2, int k2, const mpz_t m) __attribute__ ((deprecated)); 00315 00316 00331 void classic_mod(TPolynom R, int &kR, 00332 const TconstPolynom P1, int k1, 00333 const TconstPolynom P2, int k2, const mpz_t m); 00334 // Remainder of polynomial division, O(n^2) 00335 // returns P1 mod P2 in R 00336 00337 00351 void div(TPolynom Q, int &kQ, 00352 const TconstPolynom P1, const int k1, 00353 const TconstPolynom P2, const int k2, const mpz_t m); 00354 // (fast) polynomial division by multiplying with the reciprocal polynomial 00355 00356 00371 void mod(TPolynom R, int &kR, 00372 const TconstPolynom P1, int k1, 00373 const TconstPolynom P2, int k2, const mpz_t m); 00374 // polynomial remainder, fast(er) method 00375 // returns P1 modulo P2 in R 00376 /* asymptotically faster than the "naive modulo", because we can make use of 00377 fast multiplication algorithms. */ 00378 00379 00391 void multipoint_eval(mpz_t* res, 00392 const TconstPolynom P, const int k, 00393 const mpz_t* const array_of_arguments, const int size, 00394 const mpz_t m); 00395 00396 00407 int construct_polynomial_from_roots 00408 (TPolynom &res, 00409 const mpz_t* const roots_array, const int size, 00410 const mpz_t m); 00411 // task: 00412 // Creates a new polynomial using the zeros given in "roots_array"; 00413 // this polynomial will be placed in "res" and its size will be returned. 00414 // To avoid memory leaks (due to erroneous calls), we expect that 00415 // "res" is initially an NULL-pointer. 00416 // additional remark: 00417 // Sure, it would be possible to return this pointer instead of using a reference 00418 // parameter, but what if you forget to delete it later? -- Using this technique, 00419 // the programmer is at least urged to provide a valid container for our data! 00420 00421 } // namespace polynomial 00422 00423 #endif /* POLYNOMIAL_HEADER_ */