src/poly.c

Go to the documentation of this file.
00001 /*
00002    libit - Library for basic source and channel coding functions
00003    Copyright (C) 2005-2005 Vivien Chappelier, Herve Jegou
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 */
00019 
00020 /*! \defgroup poly   Polynomials related functions
00021   Copyright (C) 2005-2007 Vivien Chappelier
00022 @{
00023 */
00024 
00025 
00026 #include <it/math.h>
00027 #include <it/poly.h>
00028 #include <it/io.h>
00029 
00030 /*! \brief remove null factors from the polynomial 
00031 
00032   e.g. 0 X^2 + X + 1 becomes X + 1 */
00033 void poly_normalize (vec v)
00034 {
00035   int  i;
00036 
00037   for (i = vec_length (v) - 1; i >= 0; i--)
00038     if (v[i])
00039       break;
00040   vec_set_length (v, i + 1);
00041 }
00042 
00043 /* multiply the polynomial by X^shift.
00044    Factors with negative exponent are discarded
00045    e.g. 2X^2 + 3X + 1 shifted -1 becomes 2X + 3.
00046 */
00047 void poly_shift (vec v, int shift)
00048 {
00049   int  i;
00050 
00051   if (shift < 0) {
00052     for (i = -shift; i < vec_length (v); i++)
00053       v[i + shift] = v[i];
00054   }
00055   else {
00056     for (i = vec_length (v); i >= shift; i--)
00057       v[i] = v[i - shift];
00058     for (; i >= 0; i--)
00059       v[i] = 0;
00060   }
00061 }
00062 
00063 /* check if the polynomial is null. */
00064 int poly_is_null (vec v)
00065 {
00066   int  i;
00067 
00068   for (i = 0; i < vec_length (v); i++)
00069     if (v[i])
00070       return (0);
00071 
00072   return (1);
00073 }
00074 
00075 /* polynomial addition */
00076 vec poly_add (vec a, vec b)
00077 {
00078   int  i;
00079 
00080   if (vec_length (b) > vec_length (a)) {
00081     for (i = 0; i < vec_length (a); i++)
00082       a[i] += b[i];
00083     vec_set_length (a, vec_length (b));
00084     for (; i < vec_length (b); i++) {
00085       a[i] = b[i];
00086     }
00087   }
00088   else {
00089     for (i = 0; i < vec_length (b); i++)
00090       a[i] += b[i];
00091   }
00092   poly_normalize (a);
00093   return (a);
00094 }
00095 
00096 /* polynomial subtraction */
00097 vec poly_sub (vec a, vec b)
00098 {
00099   int  i;
00100 
00101   if (vec_length (b) > vec_length (a)) {
00102     for (i = 0; i < vec_length (a); i++)
00103       a[i] -= b[i];
00104     vec_set_length (a, vec_length (b));
00105     for (; i < vec_length (b); i++) {
00106       a[i] = -b[i];
00107     }
00108   }
00109   else {
00110     for (i = 0; i < vec_length (b); i++)
00111       a[i] -= b[i];
00112   }
00113   poly_normalize (a);
00114   return (a);
00115 }
00116 
00117 /* Laurent polynomial Euclidean division of a by b */
00118 /* This finds Q and R such that A = B Q + R X^deg_x */
00119 /* for classical polynomial division, deg_x = 0. */
00120 /* a and b are assumed to be normalized. */
00121 /* The returned remainder is not normalized. */
00122 vec _lpoly_ediv (vec a, vec b, int deg_x, vec * _q)
00123 {
00124   int  deg_a, deg_b, deg_q;
00125   vec  q;
00126   int  i, j;
00127 
00128   if (poly_deg (a) < poly_deg (b)) {
00129     *_q = vec_null;
00130     return (a);
00131   }
00132 
00133   deg_a = poly_deg (a);
00134   deg_b = poly_deg (b);
00135   deg_q = deg_a - deg_b;
00136 
00137   q = vec_new (deg_q + 1);
00138 
00139   /* set upper terms of A to zero recursively */
00140   for (i = 0; i <= (deg_q - deg_x); i++) {
00141 
00142     /* compute Q that cancels A[deg_a - i] */
00143     q[deg_q - i] = a[deg_a - i] / b[deg_b];
00144 
00145     /* subtract */
00146     for (j = 0; j <= deg_b; j++)
00147       a[deg_q - i + j] -= q[deg_q - i] * b[j];
00148   }
00149 
00150   /* set lower terms of A to zero recursively */
00151   for (i = 0; i < deg_x; i++) {
00152 
00153     /* compute Q that cancels A[i] */
00154     q[i] = a[i] / b[0];
00155 
00156     /* subtract */
00157     for (j = 0; j <= deg_b; j++)
00158       a[i + j] -= q[i] * b[j];
00159   }
00160 
00161   *_q = q;
00162 
00163   return (a);
00164 }
00165 
00166 vec lpoly_ediv (vec _a, vec _b, int deg_x, vec * _q)
00167 {
00168   vec  b, a;
00169 
00170   /* normalize input polynomials */
00171   b = vec_clone (_b);
00172   a = vec_clone (_a);
00173   poly_normalize (b);
00174   poly_normalize (a);
00175 
00176   it_assert (poly_deg (b) >= 0, "Polynomial division by zero\n");
00177 
00178   a = _lpoly_ediv (a, b, deg_x, _q);
00179 
00180   /* normalize the remainder */
00181   poly_normalize (a);
00182 
00183   vec_delete (b);
00184   return (a);
00185 }
00186 
00187 vec poly_gcd (vec _a, vec _b)
00188 {
00189   vec  b, a, t;
00190 
00191   /* normalize input polynomials */
00192   b = vec_clone (_b);
00193   a = vec_clone (_a);
00194   poly_normalize (b);
00195   poly_normalize (a);
00196 
00197   while (!poly_is_null (b)) {
00198     t = b;
00199     a = poly_mod (a, b);
00200     b = a;
00201     a = t;
00202   }
00203 
00204   vec_delete (b);
00205   return (a);
00206 }
00207 
00208 it_function (itf_polynomial)
00209 {
00210   int  i;
00211   double v;
00212   vec  poly = it_this->poly;
00213 
00214   v = poly[poly_deg (poly)];
00215   for (i = poly_deg (poly) - 1; i >= 0; i--)
00216     v = v * x + poly[i];
00217 
00218   return (v);
00219 }
00220 
00221 /*! @} */

Hosted by
Copyright (C) 2005-2006 Hervé Jégou
Vivien Chappelier
Francois Cayre
libit logo courtesy of Jonathan Delhumeau