Hierarchia klas: Wielomian i inne pojęcia alebraiczne¶
Klasa Polynomial¶
Stwórz klasę Polynomial, która będzie reprezentować funkcję \(W(x) = \sum_{i=0}^N c_i x^i\) gdzie \(N\) jest stopniem wielomianu a \(x\) dowolną liczbą rzeczywistą. Współczynniki \(c_i\) powinny być prywatnymi danymi klasy
- Konstruktor klasy
Klasa powinna mieć konstruktor, umożliwiający łatwe tworzenie wielomianów. Zadbaj o wygodę użytkowników swojej klasy! Twój konstruktor powinien zatem być przeciążony (patrz przeciążenie). Utwórz warianty umożliwiające następujące sposoby konstruowania wielomianów:
w1 = Polynomial(1, 0, 5) # Tworzy x^2 + 5 w2 = Polynomial([1, 0, 5]) # Tworzy x^2 + 5 w3 = Polynomial(w2) # Konstruktor kopiujący
- Dane prywatne
Zastanów się nad najwygodniejszą reprezentacją danych prywatnych klasy
- Wypisywanie na ekran
Napisz metodę
__str__(), która odpowiednio wydrukuje wielomian na ekranieprint(w1) # Drukuje na ekran: x^2 + 1
- Metody publiczne
Klasa
Polynomialpowinna mieć następujące metody:add(w),sub(w)imul(w), które będą odpowiednio dodawać, odejmować oraz wymnażać wielomianw, modyfikując bieżący obiekt (self). Napisz także metodydifferentiate()iintegrate(), które policzą pierwszą pochodną oraz całkę z wielomianu. Oczywiście klasaPolynomialpowinna też mieć metodęeval()obliczającą wartość wielomianu w zadanym punkcie.
Na tym etapie Twoja klasa powinna umożliwić poprawne działanie następującego programu:
w1 = Polynomial(2, 0, 1)
print(w1) # Drukuje na ekran: x^2 + 1
w2 = Polynomial([3, 2, 1])
w3 = Polynomial(w2)
w2.add(w1)
print(w2.mul(w1))
Lepsza klasa Polynomial¶
- Przeciążenie operatorów
Wykorzystaj Funkcje specjalne do zdefiniowania operatorów
+= -= *=, które zastąpią odpowiednio metody klasy:add(w),sub(w)imul(w). W tym celu wystarczy odpowiednio zmienić nazwy metod, npadd()na__iadd__(). Pamiętaj, aby metody te zwracałyself. Zdefiniuj też operatory+ - *a także operator wywołania (ang. call operator) jako metodę__call__(), który zastąpi metodęeval()- Zabezpieczanie danych prywatnych
Utwóż listę
__slots__w klasiePolynomial(Lista __slots__), aby nikt nie dodał nowych składowych do Twojej klasy- Dostęp do składowych
Utwóż getter
coefficientsudostępniający współczynniki wielomianu; dla zachowania integralności klasy metoda ta powinna zwracać głęboką kopię współczynników, ustawionych w kolejności wg. rosnących potęg.
Na tym etapie Twoja klasa powinna umożliwić poprawne działanie następującego programu:
w1 = Polynomial(2, 1)
print(w1) # Drukuje na ekran: x^2 + 1
w2 = Polynomial([3, 2, 1])
w3 = Polynomial(w2)
w2 += w1
w4 = w3 + w2
w5 = w3 - w2
w = w4 * w5
print(w2.coefficients)
Test jednostkowy dla klasy Polynomial¶
Jedną z głównych zalet obiektowego podejścia do programowania jest zamknięcie fragmentu kodu w obiekcie jako w autonomicznej całości (patrz enkapsulacja). Każdy obiekt należy jednak dokładnie przetestować. Przedstawiony poniżej plik TestPolynomial.py sprawdza działanie publicznych metod, które powinieneś zaimplementować w klasie Polynomial:
A unit test for Polynomial class
1import unittest
2
3from Polynomial import Polynomial
4
5
6class TestPolynomial(unittest.TestCase):
7
8 def setUp(self):
9 self.w1 = Polynomial([1, 2, 3, 5]) # 1*x^3 + 2*x^2 + 3*x + 5
10 self.w2 = Polynomial(5, 2, 1) # 5*x^2 + 2*x + 1
11 self.w3 = Polynomial(self.w1)
12
13 def test_coefficients(self):
14 self.assertEqual([5, 3, 2, 1], self.w1.coefficients)
15 self.assertEqual([1, 2, 5], self.w2.coefficients)
16 self.assertEqual([5, 3, 2, 1], self.w3.coefficients)
17 c = self.w3.coefficients
18 c.append(7)
19 self.assertEqual([5, 3, 2, 1], self.w3.coefficients)
20
21 def test_init(self):
22 args = [1, 2, 3, 5]
23 w = Polynomial(args)
24 args.append(7)
25 self.assertEqual([5, 3, 2, 1], w.coefficients)
26
27 def test_str(self):
28 self.assertEqual("1*x^3 + 2*x^2 + 3*x + 5", str(self.w1))
29 self.assertEqual("5*x^2 + 2*x + 1", str(self.w2))
30
31 def test_add(self):
32 w3 = self.w2 + self.w1
33 self.assertEqual([6, 5, 7, 1], w3.coefficients)
34 w3 = self.w1 + self.w2
35 self.assertEqual([6, 5, 7, 1], w3.coefficients)
36
37 def test_iadd(self):
38 w = Polynomial(self.w1)
39 c2 = self.w2.coefficients
40 w += self.w2
41 self.assertEqual([6, 5, 7, 1], w.coefficients)
42 w3 = self.w1 + self.w2
43 self.assertEqual(self.w2.coefficients, c2)
44
45 def test_sub(self):
46 w4 = Polynomial(self.w1)
47 w3 = self.w2 - self.w1
48 self.assertEqual(w4.coefficients, self.w1.coefficients) # operation should not affect operands
49 self.assertEqual([-4, -1, 3, -1], w3.coefficients)
50 w4 = self.w1 - self.w2
51 self.assertEqual([4, 1, -3, 1], w4.coefficients)
52
53 def test_mul(self):
54 w4 = Polynomial(self.w1)
55 w3 = self.w2 * self.w1
56 self.assertEqual([5, 13, 33, 20, 12, 5], w3.coefficients)
57 self.assertEqual(w4.coefficients, self.w1.coefficients) # operation should not affect operands
58
59 def test_int_math(self):
60 w3 = self.w2 * 2
61 self.assertEqual([2, 4, 10], w3.coefficients)
62
63if __name__ == '__main__':
64 unittest.main()
W szczególności test ten sprawdza integralność klasy. Na przykład metoda test_init(self) tworzy wielomian dla podanej listy współczynników, a następnie modyfikuje tą listę i sprawdza, czy wielomian nie uległ zmianie.
Wielomany Czebyszewa¶
Wieloman Czebyszewa k-tego rzędu \(T_k(x)\) zdefiniowany jest rekurencyjnie jak nastepuje:
\(\begin{matrix} T_0(x) & = & 1\\ T_1(x) & = & x\\ T_k(x) & = & 2x T_{k-1}(x) - T_{k-2}(x)\\ \end{matrix}\)
Wydrukuj na ekranie wielomian \(T_{128}(x)\). W tym celu:
- funkcja
chebyshev(k) Napisz funkcję
chebyshev(k), która zwraca listę współczynników wielomanu Czebyszewa k-tego rzędu.- Klasa
Chebyshev Zawrzyj funkcję
chebyshev(k)w klasieChebyshevjako jej statyczną składową. Klasa powinna dziedziczyć po klasiePolynomial. Ponieważ konstruktor klasyPolynomialwymaga podania współczynników tworzonego wielomianu, wykorzystaj tu napisaną uprzednio statyczną metodę.
Poniżej podaję test jednostkowy dla klasy Chebyshev:
(rozwiń kod testu jednostkowego dla klasy Chebyshev)
1import unittest
2
3from Chebyshev import Chebyshev
4
5
6class TestChebyshev(unittest.TestCase):
7
8 def test_Chebyshev(self):
9 c = Chebyshev(6)
10 self.assertEqual([-1, 0, 18, 0, -48, 0, 32], c.coefficients)
11
12if __name__ == '__main__':
13 unittest.main()
Klasa Fractional¶
Stwórz klasę Fractional, która będzie reprezentować iloraz wyrażeń.
- Konstruktor klasy
Klasa powinna mieć następujący konstruktor:
f = Fractional(1,5) # Tworzy ulamek 1/5
- Dane prywatne
Iloraz powinien przechowywać licznik oraz mianownik jako prywatne pola.
- Publiczne pola
Zdefiniuj getter dla licznika i mianownika, nazwij je
numiden- Wypisywanie na ekran
Napisz metodę
__str__(), która odpowiednio wydrukuje ułamek na ekranie. Wykorzystaj w tym celu funkcjęstr()dla licznika i mianownika- Operatory
Klasa
Fractionalpowinna udostępniać następujące operatory:+,-oraz*. Przy sprowadzaniu wyrażeń do wspólnego mianownika również korzystaj z operacji+oraz*, operujących odpowiednio na liczniku i mianowniku.
Na tym etapie Twoja klasa powinna umożliwić poprawne działanie następującego programu:
f1 = Fractional(2, 5)
f2 = Fractional(1,3)
print(f3) # Drukuje na ekran: 2/15
f3 = f1 * f2
f3 += f1
f4 = f3 - f2
Funkcje wymierne¶
Funkcja wymierna to nic więcej jak ułamek (Fractional) w którym zarówno licznik i mianownik to wielomiany
(obiekty klasy Polynomial). Poniższy kod powinien działać poprawnie:
w1 = Polynomial(1, 2, 5)
w2 = Polynomial(1,3)
f1 = Fractional(w1, w2)
f2 = Fractional(w2, w1)
print(f1 + f2)