Implementujemy liczby dualne w Pythonie. Nasza implementacja powinna być napisana w pliku dual_numbers.py.
Celem tego zadania jest zaimplementowanie klasy DualNumber w Pythonie. Liczby dualne są rozszerzeniem liczb rzeczywistych o specjalny element ‘ε’ (epsilon), taki że ε² = 0. Są one używane w automatycznym różniczkowaniu.
Liczba dualna: Liczba postaci a + bε, gdzie ‘a’ i ‘b’ są liczbami rzeczywistymi, a ε jest jednostką nieskończenie małą.
Instrukcje:
Definicja klasy:
Utwórz klasę o nazwie DualNumber.
Konstruktor __init__ powinien przyjmować dwa argumenty, real i dual, reprezentujące odpowiednio ‘a’ i ‘b’ w a + bε. Oba powinny domyślnie wynosić 0.
Zapisz te wartości jako atrybuty self.real i self.dual.
Reprezentacja jako napis:
Zaimplementuj metody __str__ i __repr__, aby zapewnić przyjazną dla użytkownika reprezentację napisową liczby dualnej. Powinna ona wyglądać odpowiednio jak “a + bε” lub “a - bε” dla __str__ i “DualNumber(a,b)” dla __repr__.
Operacje arytmetyczne:
Zaimplementuj następujące operacje arytmetyczne, aby umożliwić obliczenia na liczbach dualnych:
__add__ (+): (a + bε) + (c + dε) = (a + c) + (b + d)ε
__sub__ (-): (a + bε) - (c + dε) = (a - c) + (b - d)ε
__mul__ (): (a + bε) (c + dε) = ac + (ad + bc)ε
__truediv__ (/): (a + bε) / (c + dε) = (a/c) + ((bc - ad)/c²)ε (Załóż, że c != 0)
__pow__ (**): (a + bε)^n = a^n + na^(n-1)bε
__neg__ (-): -(a + bε) = -a - bε
Zaimplementuj prawostronne wersje tych operacji, aby obsługiwać przypadki takie jak 2 + (a + bε):
__radd__
__rsub__
__rmul__
__rtruediv__
__rpow__
Operacje porównania:
Zaimplementuj następujące operacje porównania:
__eq__ (==): (a + bε) == (c + dε) jeśli a == c i b == d
__ne__ (!=): (a + bε) != (c + dε) jeśli a != c lub b != d
Konwersja na int i float:
Zaimplementuj metody __int__ i __float__, aby umożliwić konwersję liczby dualnej na typy int i float. Konwersja powinna zwracać tylko część rzeczywistą liczby dualnej.
Dodatkowe funkcje matematyczne (opcjonalne):
Zaimplementuj inne funkcje matematyczne jako metody klasy:
sqrt(z): Pierwiastek kwadratowy liczby dualnej.
exp(z): Funkcja wykładnicza liczby dualnej.
sin(z): Sinus liczby dualnej.
cos(z): Cosinus liczby dualnej.
Poniżej znajduje się przykład użycia klasy DualNumber, (kod kliencki). Twoja implementacja powinna umożliwić poprawne działanie tego kodu.
Show the code
from dual_numbers import DualNumber, epsilonfuncje_zaimplementowane =False# Utwórz kilka liczb dualnycha = DualNumber(2, 3) # 2 + 3εb = DualNumber(1, 4) # 1 + 4εc = DualNumber(5, 0) # 5 + 0ε (odpowiednik liczby rzeczywistej 5)d =1+2* epsilon # 1 + 2ε# Wypisz liczby dualneprint("Liczba dualna a:", a)print("Liczba dualna b:", b)print("Epsilon:", epsilon)# Podstawowe operacje arytmetyczneprint("Dodawanie:", a + b)print("Odejmowanie:", a - b)print("Mnożenie:", a * b)print("Dzielenie:", a / b)print("Potęgowanie:", a**2)print("Negacja", -a)# Operacje prawostronneprint("Dodawanie prawe:", 1+ a)print("Odejmowanie prawe:", 5- a)print("Mnożenie prawe:", 2* a)print("Dzielenie prawe:", 10/ a)print("Potęgowanie prawe", 2**a)# Operacje porównaniaprint("Równość:", a == b)print("Nierówność:", a != b)print("Równość:", a == DualNumber(2, 3))# Konwersja na int i floatprint("Konwersja na int:", int(a))print("Konwersja na float:", float(a))# Opcjonalne funkcje na liczbach dualnychif funcje_zaimplementowane:print("Pierwiastek kwadratowy z a:", DualNumber.sqrt(a))print("Funkcja wykładnicza z a:", DualNumber.exp(a))print("Sinus z a:", DualNumber.sin(a))print("Cosinus z a:", DualNumber.cos(a))
Rozwiązanie
Show the code
from __future__ import annotationsimport mathclass DualNumber:"""Reprezentuje liczbę dualną postaci a + bε."""def__init__(self, real: float=0.0, dual: float=0.0) ->None:"""Inicjalizuje liczbę dualną. Args: real: Część rzeczywista (a). Domyślnie 0.0. dual: Część dualna (b). Domyślnie 0.0. """self.real =float(real)self.dual =float(dual)def__str__(self) ->str:"""Zwraca reprezentację łańcuchową liczby dualnej.""" sign ="+"ifself.dual >=0else"-"returnf"{self.real}{sign}{abs(self.dual)}ε"def__repr__(self) ->str:"""Zwraca oficjalną reprezentację łańcuchową liczby dualnej."""returnf"DualNumber({self.real}, {self.dual})"def__add__(self, other: DualNumber |float) -> DualNumber:"""Dodaje dwie liczby dualne lub liczbę dualną i liczbę rzeczywistą."""ifisinstance(other, DualNumber):return DualNumber(self.real + other.real, self.dual + other.dual)ifisinstance(other, int|float):return DualNumber(self.real + other, self.dual)returnNotImplementeddef__radd__(self, other: float) -> DualNumber:"""Obsługuje dodawanie z liczbą rzeczywistą po lewej stronie. other + self """returnself+ otherdef__sub__(self, other: DualNumber |float) -> DualNumber:"""Odejmuje dwie liczby dualne lub liczbę dualną i liczbę rzeczywistą."""ifisinstance(other, DualNumber):return DualNumber(self.real - other.real, self.dual - other.dual)ifisinstance(other, int|float):return DualNumber(self.real - other, self.dual)returnNotImplementeddef__rsub__(self, other: float) -> DualNumber:"""Obsługuje odejmowanie z liczbą rzeczywistą po lewej stronie."""return DualNumber(other -self.real, -self.dual)def__mul__(self, other: DualNumber |float) -> DualNumber:"""Mnoży dwie liczby dualne lub liczbę dualną i liczbę rzeczywistą."""ifisinstance(other, DualNumber): real_part =self.real * other.real dual_part = (self.real * other.dual) + (self.dual * other.real)return DualNumber(real_part, dual_part)ifisinstance(other, int|float):return DualNumber(self.real * other, self.dual * other)returnNotImplementeddef__rmul__(self, other: float) -> DualNumber:"""Obsługuje mnożenie z liczbą rzeczywistą po lewej stronie."""returnself* otherdef__truediv__(self, other: DualNumber |float) -> DualNumber:"""Dzieli dwie liczby dualne lub liczbę dualną i liczbę rzeczywistą."""ifisinstance(other, DualNumber):if other.real ==0: msg ="Dzielenie przez zero"raiseZeroDivisionError(msg) real_part =self.real / other.real dual_part = (self.dual * other.real -self.real * other.dual) / ( other.real**2 )return DualNumber(real_part, dual_part)ifisinstance(other, int|float):if other ==0: msg ="Dzielenie przez zero"raiseZeroDivisionError(msg)return DualNumber(self.real / other, self.dual / other)returnNotImplementeddef__rtruediv__(self, other: float) -> DualNumber:"""Obsługuje dzielenie z liczbą rzeczywistą po lewej stronie."""ifself.real ==0: msg ="Dzielenie przez zero"raiseZeroDivisionError(msg) real_part = other /self.real dual_part = (0- other *self.dual) / (self.real**2)return DualNumber(real_part, dual_part)def__pow__(self, n: float) -> DualNumber:"""Podnosi liczbę dualną do potęgi n (n jest liczbą całkowitą lub zmiennoprzecinkową)."""ifisinstance(n, int|float): real_part =self.real**n dual_part = n * (self.real ** (n -1)) *self.dualreturn DualNumber(real_part, dual_part)returnNotImplementeddef__rpow__(self, other: float) -> DualNumber:"""Obsługuje przypadek, gdy liczba rzeczywista jest podnoszona do potęgi liczby dualnej."""ifisinstance(other, int|float): real_part = other**self.real dual_part = real_part * math.log(other) *self.dualreturn DualNumber(real_part, dual_part)returnNotImplementeddef__neg__(self) -> DualNumber:"""Zwraca negację liczby dualnej."""return DualNumber(-self.real, -self.dual)def__eq__(self, other: DualNumber) ->bool:"""Sprawdza, czy dwie liczby dualne są równe."""ifisinstance(other, DualNumber):returnself.real == other.real andself.dual == other.dualreturnFalsedef__ne__(self, other: DualNumber) ->bool:"""Sprawdza, czy dwie liczby dualne nie są równe."""returnnotself== otherdef__int__(self) ->int:"""Konwertuje liczbę dualną na liczbę całkowitą (zwraca część rzeczywistą)."""returnint(self.real)def__float__(self) ->float:"""Konwertuje liczbę dualną na liczbę zmiennoprzecinkową (zwraca część rzeczywistą)."""returnfloat(self.real)@staticmethoddef sqrt(z: DualNumber) -> DualNumber:"""Oblicza pierwiastek kwadratowy z liczby dualnej."""if z.real <0: msg ="Pierwiastek kwadratowy z ujemnej części rzeczywistej nie jest zdefiniowany dla liczb dualnych w tej implementacji"raiseValueError( msg, ) real_part = math.sqrt(z.real) dual_part = z.dual / (2* real_part) if real_part !=0else0return DualNumber(real_part, dual_part)@staticmethoddef exp(z: DualNumber) -> DualNumber:"""Oblicza funkcję wykładniczą liczby dualnej.""" real_part = math.exp(z.real) dual_part = real_part * z.dualreturn DualNumber(real_part, dual_part)@staticmethoddef sin(z: DualNumber) -> DualNumber:"""Oblicza sinus liczby dualnej.""" real_part = math.sin(z.real) dual_part = math.cos(z.real) * z.dualreturn DualNumber(real_part, dual_part)@staticmethoddef cos(z: DualNumber) -> DualNumber:"""Oblicza cosinus liczby dualnej.""" real_part = math.cos(z.real) dual_part =-math.sin(z.real) * z.dualreturn DualNumber(real_part, dual_part)epsilon = DualNumber(0, 1) # Nieskończenie mała jednostka epsilon