source: comparacioncriptosistemas/polynomial.H @ 1b57940

interfaz
Last change on this file since 1b57940 was 1b57940, checked in by Alejandro <amujica@…>, 9 years ago

Primeros intentos

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2  Copyright (C) 2015
3  Alejandro Mujica (amujica en cenditel.gob.ve)
4  José Ángel Contreras (jancontreras en cenditel.gob.ve)
5  Antonio Araujo (aaraujo en cenditel.gob.ve)
6  Pedro Buitrago (pbuitrago en cenditel.gob.ve)
7 
8  CENDITEL Fundación Centro Nacional de Desarrollo e Investigación en
9  Tecnologías Libres
10 
11  Este programa es software libre; Usted puede usarlo bajo los términos de la
12  licencia de software GPL versión 2.0 de la Free Software Foundation.
13 
14  Este programa se distribuye con la esperanza de que sea útil, pero SIN
15  NINGUNA GARANTÍA; tampoco las implícitas garantías de MERCANTILIDAD o
16  ADECUACIÓN A UN PROPÓSITO PARTICULAR.
17  Consulte la licencia GPL para más detalles. Usted debe recibir una copia
18  de la GPL junto con este programa; si no, escriba a la Free Software
19  Foundation Inc. 51 Franklin Street,5 Piso, Boston, MA 02110-1301, USA.
20*/
21
22/*
23  Este archivo contiene la definición e implementación de una clase tipo
24  plantilla para representar polinomios.
25
26  Creado por:        Alejandro J. Mujica
27  Fecha de creación:
28*/
29
30
31# ifndef POLYNOMIAL_H
32# define POLYNOMIAL_H
33
34# include <stdexcept>
35# include <sstream>
36# include <vector>
37# include <limits>
38
39# include<iostream>
40
41/**
42 *  Plantilla para representar polinomios con tipo de coeficientes paramétrico.
43 *
44 *  @param Number_Type El tipo de dato para los coeficientes. Debe pertenecer
45 *                     a los tipos aritméticos de la biblioteca estándar de C++.
46 *                     Por omisión es de tipo double.
47 *
48 *  @author Alejandro Mujica     (amujica en cenditel punto gob punto ve).
49 *  @author José Angel Contreras (jancontreras en cenditel punto gob punto ve).
50 */
51template <typename Number_Type = double>
52class Polynomial
53{
54public:
55  /// Tipo de conjunto para el polinomio.
56  typedef std::vector<Number_Type> pol_t;
57  /// Tipo de número para el grado.
58  typedef typename pol_t::size_type  degree_t;
59  /// Tipo de número para los coeficientes.
60  typedef typename pol_t::value_type number_t;
61
62private:
63  degree_t deg;
64  pol_t    pol;
65
66public:
67  /// Construcción de un polinomio dado un grado.
68  Polynomial(const degree_t & _deg = degree_t(0));
69
70  /// Construcción por medio de una lista de inicialización.
71  Polynomial(const std::initializer_list<number_t> &);
72
73  /// Constructor copia
74  Polynomial(const Polynomial &);
75
76  /// Constructor de movimiento (move semantic)
77  Polynomial(Polynomial &&);
78
79  /// Retorna el grado del polinomio.
80  const degree_t & degree() const
81  {
82    return deg;
83  }
84
85  /**
86   *  Retorna el coeficiente de la posición dada.
87   *
88   *  @param exp Grado del coeficiente deseado.
89   *  @return Coeficiente de la posición dada.
90   *  @throw overflow_error si el exponente es mayor que el grado del polinomio.
91   */
92  const number_t & get_coefficient(const degree_t & exp) const
93  {
94    if (exp > deg)
95      throw std::overflow_error("exp is greater than polynomial degree");
96
97    return pol.at(deg - exp);
98  }
99
100  /**
101   *  Asigna valor al coeficiente de la posición dada.
102   *
103   *  @param exp Grado del coeficiente deseado.
104   *  @param value Valor que se asignará al coeficiente.
105   *  @throw overflow_error si el exponente es mayor que el grado del polinomio.
106   */
107  void set_coefficient(const degree_t & exp, const number_t & value)
108  {
109    if (exp > deg)
110      throw std::overflow_error("exp is greater than polynomial degree");
111
112    pol.at(deg - exp) = value;
113  }
114
115  /// Determina si el polinomio es nulo.
116  bool is_null() const;
117
118  bool operator ! () const;
119
120  Polynomial operator + (const Polynomial &);
121
122  Polynomial & operator += (const Polynomial &);
123
124  Polynomial operator - (const Polynomial &);
125
126  Polynomial & operator -= (const Polynomial &);
127
128  Polynomial operator * (const Polynomial &);
129
130  Polynomial operator / (const Polynomial &);
131
132  Polynomial operator % (const Polynomial &);
133
134  Polynomial & operator = (const Polynomial &);
135
136  Polynomial & operator = (Polynomial &&);
137
138  bool operator == (const Polynomial &) const;
139
140  bool operator != (const Polynomial &) const;
141
142  /// Retorna una representación del polinomio en cadena.
143  std::string to_string(const char & var = 'x');
144};
145
146/**
147 *  Constructor que funge de paramétrico y por omisión al mismo tiempo.
148 *
149 *  @param _deg Grado del polinomio. Por omisión es 0.
150 */
151template <typename Number_Type>
152Polynomial<Number_Type>::Polynomial(const Polynomial::degree_t & _deg)
153  : deg(_deg), pol(deg + degree_t(1), number_t(0))
154{
155  // Empty
156}
157
158/**
159 *  Construye un polinomio dada una lista de inicialización.
160 *
161 *  Para inicializar el polinomio se deben pasar los valores de los coeficientes
162 *  encerrados por llaves y separados por coma (,). Debe escribirse el polinomio
163 *  completo.
164 *  Por ejemplo, si se quiere construir el polinomio
165 *  p = 1x^5 + 2x^4 + 3x^3 + 4x^2 + 5x + 6
166 *
167 *  La instanciación debe realizarse de la siguiente manera:
168 *  <code>Polynomial<> p = { 1, 2, 3, 4, 5, 6 };</code>
169 *
170 *  @param l Lista de inicialización del polinomio.
171 */
172template <typename Number_Type>
173Polynomial<Number_Type>::Polynomial(const std::initializer_list<number_t> & l)
174  : deg(degree_t(l.size()) - degree_t(1)), pol(l)
175{
176  // Empty
177}
178
179template <typename Number_Type>
180Polynomial<Number_Type>::Polynomial(const Polynomial & p)
181  : deg(p.deg), pol(p.pol)
182{
183  // Empty
184}
185
186template <typename Number_Type>
187Polynomial<Number_Type>::Polynomial(Polynomial && p)
188  : deg(degree_t(0)), pol(deg + degree_t(1), number_t(0))
189{
190  std::swap(deg, p.deg);
191  std::swap(pol, p.pol);
192}
193
194
195/**
196 *  Determina si un polinomio es nulo.
197 *  Un polinomio es nulo si todos sus coeficientes son cero.
198 *
199 *  @return <code>true</code> si el polinomio es nulo y <code>false</code> en
200 *          caso contrario.
201 */
202template <typename Number_Type>
203bool Polynomial<Number_Type>::is_null() const
204{
205  for (const number_t & c : pol)
206    if (c != number_t(0))
207      return false;
208  return true;
209}
210
211template <typename Number_Type>
212bool Polynomial<Number_Type>::operator ! () const
213{
214  return is_null();
215}
216
217template <typename Number_Type>
218Polynomial<Number_Type>
219Polynomial<Number_Type>::operator + (const Polynomial & p)
220{
221  const degree_t & min_degree = std::min(deg, p.deg);
222  const degree_t & max_degree = std::max(deg, p.deg);
223
224  Polynomial ret(max_degree);
225
226  for (degree_t i = degree_t(0); i <= min_degree; ++i)
227    ret.set_coefficient(i, get_coefficient(i) + p.get_coefficient(i));
228
229  const Polynomial & max_degree_pol = deg > p.deg ? *this : p;
230
231  for (degree_t i = min_degree + degree_t(1); i <= max_degree; ++i)
232    ret.set_coefficient(i, max_degree_pol.get_coefficient(i));
233
234  return ret;
235}
236
237template <typename Number_Type>
238Polynomial<Number_Type> &
239Polynomial<Number_Type>::operator += (const Polynomial & p)
240{
241  *this = *this + p;
242  return *this;
243}
244
245template <typename Number_Type>
246Polynomial<Number_Type>
247Polynomial<Number_Type>::operator - (const Polynomial & p)
248{
249  const degree_t & min_degree = std::min(deg, p.deg);
250  const degree_t & max_degree = std::max(deg, p.deg);
251
252  Polynomial ret(max_degree);
253
254  for (degree_t i = degree_t(0); i <= min_degree; ++i)
255    ret.set_coefficient(i, get_coefficient(i) - p.get_coefficient(i));
256
257  Polynomial & max_degree_pol = deg > p.deg ? *this : p;
258
259  char sign = &max_degree_pol == this ? 1 : -1;
260
261  for (degree_t i = min_degree + degree_t(1); i <= max_degree; ++i)
262    ret.set_coefficient(i, sign * max_degree_pol.get_coefficient(i));
263
264  return ret;
265}
266
267template <typename Number_Type>
268Polynomial<Number_Type> &
269Polynomial<Number_Type>::operator -= (const Polynomial & p)
270{
271  *this = *this - p;
272  return *this;
273}
274
275template <typename Number_Type>
276Polynomial<Number_Type>
277Polynomial<Number_Type>::operator * (const Polynomial & p)
278{
279  Polynomial ret(deg + p.deg);
280
281  for (degree_t i = degree_t(0); i <= deg; ++i)
282    for (degree_t j = degree_t(0); j < p.deg; ++j)
283      ret.set_coefficient(i + j,
284        ret.get_coefficient(i + j) + get_coefficient(i) * p.get_coefficient(j));
285       
286
287  return ret;
288}
289
290template <typename Number_Type>
291Polynomial<Number_Type>
292Polynomial<Number_Type>::operator / (const Polynomial & p)
293{
294  if (p.is_null())
295    throw std::logic_error("Polynomial devision by 0");
296
297  if (p.deg > deg)
298    return Polynomial();
299
300  Polynomial ret(deg - p.deg);
301
302  number_t inv = number_t(0);
303
304  if (p.deg > 0)
305    {
306      Polynomial tmp = *this;
307
308      degree_t last = p.deg;
309
310      while (last > degree_t(0) and p.get_coefficient(last) == number_t(0))
311        --last;
312
313      inv = number_t(1) / p.get_coefficient(last);
314
315      for (degree_t i = tmp.deg; i >= p.deg; --i)
316        {
317          ret.set_coefficient(i - p.deg, tmp.get_coefficient(i) * inv);
318
319          for (degree_t j = degree_t(0); j <= p.deg; ++j) 
320            tmp.set_coefficient(i - j,
321              tmp.get_coefficient(i - j) - p.get_coefficient(p.deg - j) *
322              ret.get_coefficient(i - p.deg));
323        }
324
325      return ret;
326    }
327
328  degree_t first = degree_t(0);
329
330  while (first <= p.deg and p.get_coefficient(first) == number_t(0))
331    ++first;
332
333  inv = number_t(1) / p.get_coefficient(first);
334
335  for (number_t & c : ret.pol)
336    c *= inv;
337
338  return ret;
339}
340
341template <typename Number_Type>
342Polynomial<Number_Type>
343Polynomial<Number_Type>::operator % (const Polynomial & p)
344{
345  if (p.is_null()) 
346    throw std::logic_error("Polynomial denominator = 0");
347
348  if (p.deg == degree_t(0))
349    return Polynomial();
350
351  Polynomial ret = *this;
352
353  degree_t last = p.deg;
354
355    while (last > degree_t(0) and p.get_coefficient(last) == number_t(0))
356      --last;   
357
358  number_t inv = number_t(1) / p.get_coefficient(last);
359
360  for (degree_t i = ret.deg; i >= p.deg; --i)
361    {
362      number_t q = ret.get_coefficient(i) * inv;
363
364      for (degree_t j = degree_t(0); j <= p.deg; ++j) 
365        ret.set_coefficient(i - j, ret.get_coefficient(i - j) -
366          p.get_coefficient(p.deg - j) * q);
367    }
368
369  while (ret.deg > degree_t(0) and ret.get_coefficient(ret.deg) == number_t(0))
370    --ret.deg;
371
372  return ret;
373}
374
375template <typename Number_Type>
376Polynomial<Number_Type> &
377Polynomial<Number_Type>::operator = (const Polynomial & p)
378{
379  if (&p == this)
380    return *this;
381
382  deg = p.deg;
383  pol = p.pol;
384
385  return *this;
386}
387
388template <typename Number_Type>
389Polynomial<Number_Type> &
390Polynomial<Number_Type>::operator = (Polynomial && p)
391{
392  std::swap(deg, p.deg);
393  std::swap(pol, p.pol);
394
395  return *this;
396}
397
398template <typename Number_Type>
399bool Polynomial<Number_Type>::operator == (const Polynomial & p) const
400{
401  if (deg != p.deg)
402    return false;
403
404  for (degree_t i = degree_t(0); i <= deg; ++i)
405    if (pol.at(i) != p.pol.at(i))
406      return false;
407
408  return true;
409}
410
411template <typename Number_Type>
412bool Polynomial<Number_Type>::operator != (const Polynomial & p) const
413{
414  return not (*this == p);
415}
416
417template <typename Number_Type>
418std::string Polynomial<Number_Type>::to_string(const char & var)
419{
420  std::stringstream sstr;
421
422  if (deg > degree_t(1))
423    for (degree_t i = degree_t(0); i < deg - degree_t(1); ++i)
424      sstr << pol.at(i) << var << '^' << deg - i << " + ";
425
426  if (deg > degree_t(0))
427    sstr << pol.at(deg - degree_t(1)) << var << " + ";
428
429  sstr << pol.at(deg);
430
431  return sstr.str();
432}
433
434# endif // POLYNOMIAL_H
435
Note: See TracBrowser for help on using the repository browser.