Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs
Вначале
рассмотрим еще один способ формирования объектов Fraction на основе
значений типа float. Например, нам
требуется приближенно описать число пи:
pi = math.pi # 3.141592653589793
с помощью класса
Fraction. Если просто
записать команду:
pf = Fraction(pi) # Fraction(884279719003555, 281474976710656)
то получим
большие значения в числителе и знаменателе. Конечно, они наилучшим образом
описывают заданное значение pi. Но иметь такие величины в итоговых
результатах вычислений не всегда удобно. Поэтому можно задать ограничение
максимального значения знаменателя, получить более информативную дробь, но с
менее точным значением исходного вещественного числа. Задается это ограничение
с помощью метода limit_denominator() следующим
образом:
pf = Fraction(pi) # Fraction(884279719003555, 281474976710656)
pf2 = pf.limit_denominator() # Fraction(3126535, 995207)
Этот метод
возвращает новый объект класса Fraction с заданным ограниченным
значением знаменателя. По умолчанию установлена величина max_denominator=1000000.
В итоге получаем эквивалентное значение числа пи, равное:
float(pf2) # 3.1415926535886505
pi # 3.141592653589793
Как видите,
значения немного различаются, но дробь стала короче. Давайте еще больше ее
сократим, например, так:
pf2 = pf.limit_denominator(10) # Fraction(22, 7)
Имеем довольно
аккуратную дробь (знаменатель не превышает значения 10), но с еще менее точным
значением числа пи:
float(pf2) # 3.142857142857143
pi # 3.141592653589793
Вот так можно
делать различные аппроксимации вещественных чисел обыкновенными дробями.
Использование функций с объектами Fraction
К объектам
класса Fraction применимы и
некоторые обычные встроенные функции языка Python. Пусть,
например, у нас имеются следующие дроби:
a = Fraction('5/2')
b = Fraction(19, 123)
c = Fraction('-7/2')
Тогда функция round() возвратит
значения:
round(a) # 2
round(b, 2) # Fraction(3, 20)
round(b, 3) # Fraction(77, 500)
По сути, при
округлении дробей получаем либо целое число, либо дробь, которая наиболее точно
описывает соответствующую конечную десятичную дробь. Например, число b можно
представить в виде:
b = 19/123 = 0.15447154471544716
Округляя по
правилам школьной математики это значение, имеем:
round(b, 2) # 0.15 = 3/20
round(b, 3) # 0.154 = 77/500
Это поведение
заложено в магическом методе __round__() класса Fraction. По аналогии в
методе __abs__() описан
алгоритм вычисления модуля дробей. Например:
Помимо этого с
объектами класса Fraction можно использовать функции
стандартного модуля math:
math.trunc(a) # 2
math.floor(a) # 2
math.ceil(a) # 3
Однако, обратите
внимание, что они обрабатывают объекты Fraction, как обычные
числа, со всеми вытекающими последствиями. Например:
math.sqrt(a) # 1.5811388300841898
math.sin(a) # 0.5984721441039564
Во всех этих
функциях объекты Fraction сначала преобразуются к
вещественному типу float:
и только потом,
происходят вычисления.
Помимо функций round(), abs(), trunk(), floor(), ceil() с объектами
класса Fraction можно
использовать и некоторые другие встроенные функции языка Python. Например,
пусть имеется следующий набор дробей:
lst = [Fraction(x, y) for x, y in zip((1, 5, -7, 11, -13, 19), (2, 4, 8, 6, 3, 20))]
Здесь
формируется список из объектов:
[Fraction(1, 2),
Fraction(5, 4), Fraction(-7, 8), Fraction(11, 6), Fraction(-13, 3),
Fraction(19, 20)]
С этим списком
можно выполнять следующие операции:
sum(lst) # Fraction(-27, 40)
tuple(filter(lambda x: x.numerator < 10, lst)) # (Fraction(1, 2), Fraction(5, 4), Fraction(-7, 8), Fraction(-13, 3))
list(map(abs, lst)) # [Fraction(1, 2), Fraction(5, 4), Fraction(7, 8), Fraction(11, 6), Fraction(13, 3), Fraction(19, 20)]
sorted(lst) # [Fraction(-13, 3), Fraction(-7, 8), Fraction(1, 2), Fraction(19, 20), Fraction(5, 4), Fraction(11, 6)]
max(lst) # Fraction(11, 6)
min(lst) # Fraction(-13, 3)
Пример нахождения корней квадратного уравнения
В заключение
этого занятия давайте рассмотрим конкретный пример использования класса Fraction. Первое, что
приходит в голову, это вычисление корней квадратного уравнения, т.к. там вполне
могут получаться несокращаемые дроби. Программу для решения этой задачи можно
записать следующим образом:
from fractions import Fraction
import math
a, b, c = map(int, input().split())
D = b * b - 4 * a * c
if D > 0:
sqrt_D = Fraction(math.sqrt(D)).limit_denominator()
root1 = (-b + sqrt_D) / (2 * a)
root2 = (-b - sqrt_D) / (2 * a)
result = f"Квадратное уравнение имеет два корня:\nx1 = {root1}\nx2 = {root2}"
elif D == 0:
root = Fraction(-b, (2 * a))
result = f"Квадратное уравнение имеет один корень:\nx = {root}"
else:
result = "Квадратное уравнение не имеет действительных корней."
print(result)
Вначале вводятся
три целых числа a, b, c – коэффициенты
квадратного уравнения. Затем, вычисляется дискриминант и проверяется на больше,
равно и меньше нуля. Если D > 0, то имеем два действительных
корня. Первым делом нужно вычислить квадратный корень из дискриминанта. Для
этого используем стандартную функцию math.sqrt(), затем на
основе вещественного значения формируем дробь с ограничением по знаменателю
(чтобы дробь не получалась слишком большой). В итоге переменная sqrt_D ссылается на
объект класса Fraction и дальнейшие
целочисленные операции гарантированно будут давать объекты этого класса.
Если же
дискриминант равен нулю, то вычисления становятся гораздо проще. Здесь можно
сразу сформировать дробь, как результат вычислений. В последнем варианте, когда
D < 0,
формируем строку с сообщением отсутствия действительных корней.
Если после запуска
программы ввести значения:
3 5 2
то на выходе
получим корни в виде дробей:
x1
= -2/3
x2 = -1
Обратите
внимание, что значение -2/3 не может быть представлено конечной десятичной
дробью. И если бы вычисления выполнялись на уровне типа float, то результатом
были бы числа:
x1
= -0.6666666666666666
x2 = -1.0
С математической
точки зрения это менее информативный результат. Но благодаря применению класса Fraction мы получаем
вполне понятные обыкновенные дроби.
Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs