Абстракция данных - это методология, которая позволяет отделить способ использования составного объекта данных от деталей того, как он составлен из элементарных данных. [SICP 2.1] То есть используя данные, наши программы не должны делать о них никаких предположений, кроме абсолютно необходимых для выполнения поставленной задачи. В тоже время конкретное представление данных определяется независимо от программ, которые эти данные используют.
В книге SICP интерфейсом между двумя частями системы служит набор процедур, называемых селекторами и конструкторами, реализующих абстрактные данные в терминах конкретного представления. Мы тоже начнем с такого подхода.
Есть простые задания, средние и сложные. За каждое из них можно получить разное количество баллов. Можно не тратить время на простое задание и делать сложное, чтобы получить много баллов и шанс на автомат.
Если вы умеете, делайте всё на классах. Переопределяйте магические методы, чтобы переопределить операторы(суммы, сравнение и прочее). Выбрасывайте исключения, если надо(деление на 0). В IDEA можете нажать "generate" -> "override methods" и она покажет вам список всех магических методов, которые вам надо будет переопределить.
Как делать классы можно прочитать тут или в официальной документации. Вам, возможно, будет интересно как переопределить операторы в Python, тогда вам сюда.
Требуется создать абстракцию рациональных чисел с возможностью: создавать, складывать, вычитать, умножать, делить, сравнивать, печатать и превращать их в float number. Результаты должны быть всегда с наименьшим знаменателем (алгоритм Евклида в помощь). Целую часть выделять не надо.
Итого, нужен тип данных, который реализует следующие правила:
$$ \begin{aligned}\frac{n_1}{d_1} + \frac{n_2}{d_2} = \frac{n_1 d_2 + n_2 d_1}{d_1 d_2} \\\frac{n_1}{d_1} - \frac{n_2}{d_2} = \frac{n_1 d_2 - n_2 d_1}{d_1 d_2} \\\frac{n_1}{d_1} * \frac{n_2}{d_2} = \frac{n_1 n_2}{d_1 d_2} \\\frac{n_1}{d_1} / \frac{n_2}{d_2} = \frac{n_1 d_2}{d_1 n_2} \\{\frac{n_1}{d_1} = \frac{n_2}{d_2}} \Longleftrightarrow {n_1 d_2 = n_2 d_1} \\\end{aligned} $$
Вам скорее всего понадобится создать функцию make_rat(n1, d1)
, которая вернёт нечто. Например, словарь методов, какой-то объект или еще что-то. В качестве базового типа предлагается использовать tuple
. Если вы умеете, можете сделать всё на основе классов.
Вы можете использовать эти тесты, если работает с классами. Вам нужно будет переопределить магические методы, чтобы создать свои собственные операторы. Например, __add__
для сложения.
import unittest
class Fraction:
pass
class TestFraction(unittest.TestCase):
def testEg(self):
self.assertTrue(Fraction(1, 2) == Fraction(-3, -6))
self.assertTrue(Fraction(9, 15) == Fraction(6, 10))
self.assertTrue(Fraction(1, 3) == Fraction(1, 3))
def testLt(self):
self.assertTrue(Fraction(1, 2) < Fraction(2, 3))
self.assertTrue(Fraction(-1, 2) < Fraction(1, 2))
self.assertTrue(Fraction(0, 2) < Fraction(2, 3))
def testGt(self):
self.assertTrue(Fraction(2, 3) > Fraction(1, 3))
def testGe(self):
self.assertTrue(Fraction(2, 3) >= Fraction(1, 3))
self.assertTrue(Fraction(2, 3) >= Fraction(4, 6))
def testLe(self):
self.assertTrue(Fraction(1, 2) <= Fraction(2, 3))
self.assertTrue(Fraction(2, 3) <= Fraction(2, 3))
def testFloat(self):
self.assertEqual(float(Fraction(1, 2)),0.5)
self.assertEqual(float(Fraction(-1, 5)), -0.2)
self.assertEqual(float(Fraction(10, 2)), 5)
self.assertEqual(float(Fraction(3, -8)), -0.375)
def testADD(self):
self.assertEqual(Fraction(1, 2) + Fraction(1, 3), Fraction(5, 6))
self.assertEqual(Fraction(1, 2) + Fraction(1, 6), Fraction(2, 3))
self.assertEqual(Fraction(1, 2) + Fraction(1, -3), Fraction(1, 6))
def testSUB(self):
self.assertEqual(Fraction(1, 2) - Fraction(1, 3), Fraction(1, 6))
self.assertEqual(Fraction(1, 6) + Fraction(1, 2), Fraction(-1, 3))
def testSUB(self):
self.assertEqual(Fraction(1, 2) - Fraction(1, 3), Fraction(1, 6))
self.assertEqual(Fraction(1, 6) - Fraction(1, 2), Fraction(-1, 3))
self.assertEqual(Fraction(1, 3) - Fraction(1, 3), Fraction(0, 3))
def testMUL(self):
self.assertEqual(Fraction(1, 2) * Fraction(1, 3), Fraction(1, 6))
self.assertEqual(Fraction(1, 2) * Fraction(2, 1), Fraction(1, 1))
self.assertEqual(Fraction(1, 2) * Fraction(-1, 2), Fraction(-1, 4))
self.assertEqual(Fraction(-1, 2) * Fraction(1, -2), Fraction(1, 4))
def testDIV(self):
self.assertEqual(Fraction(1, 2) / Fraction(1, 2), Fraction(1, 1))
self.assertEqual(Fraction(1, 2) / Fraction(1, 3), Fraction(3, 2))
def testZiro(self):
try:
Fraction(2, 0)
self.assertTrue(False)
except(ArithmeticError):
pass
if __name__ == '__main__':
unittest.main()
Идея появилась из проблем инженеров. У них принято характеристики физических объектов описывать в рамках некоторых интервалов. Например, сопротивление резистора бывает 6.8 Ом с погрешностью 10%, что значит сопротивление лежит в интервале [6.12;7.48] Ом
.
Необходимо разработать абстрактную структуру данных, на которой возможны все арифметические операции: сложение, вычитание, умножение, деление. И дополнительные функции: создание, сравнение(проверка равенства), форматирование в красивой форме, вычисление радиуса погрешности (в примере это 0.68).
Например: резистор R1=[6.8;10%]Ом
подключен параллельно к резистору R2=[4.7;5%]Ом
, тогда сопротивление их комбинации будет R3=[2.58;2.97]Ом
.