Как найти период дроби python

0 / 0 / 0

Регистрация: 03.11.2019

Сообщений: 36

1

Период у дроби

14.11.2019, 18:02. Показов 14209. Ответов 7


Студворк — интернет-сервис помощи студентам

Найти период бесконечной периодической дроби. Если десятичная дробь конечна, её период — цифра 0.
Период должен начинаться с той цифры, которая является первой повторяющейся при выписывании бесконечной десятичной дроби.

Пример 1
Ввод
11
Вывод
09
Пример 2
Ввод
15
Вывод
6



0



grizlik78

Эксперт С++

2378 / 1662 / 279

Регистрация: 29.05.2011

Сообщений: 3,395

14.11.2019, 18:54

2

Возможно есть хитрые, красивые и эффективные алгоритмы, я же просто реализовал деление «уголком».

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
n = int(input())
 
first_pos = {}
position = 0
period = ""
remainder = 1
 
while not (remainder in first_pos):
    first_pos[remainder] = position
    period += str(remainder // n)
    remainder = (remainder % n) * 10
    position += 1
    
period = period[first_pos[remainder]:]
 
print(period)



0



0 / 0 / 0

Регистрация: 03.11.2019

Сообщений: 36

14.11.2019, 20:31

 [ТС]

3

grizlik78, тут нужно списки использовать, можете сказать что означает first_pos = {}?



0



grizlik78

Эксперт С++

2378 / 1662 / 279

Регистрация: 29.05.2011

Сообщений: 3,395

14.11.2019, 20:38

4

Это словарь. dict. В принципе, заменить списком не сложно, хотя эффективность ещё снизится.

Добавлено через 3 минуты

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
n = int(input())
 
remainders = []
period = ""
remainder = 1
 
while not (remainder in remainders):
    remainders.append(remainder)
    period += str(remainder // n)
    remainder = (remainder % n) * 10
    
period = period[remainders.index(remainder):]
 
print(period)



0



0 / 0 / 0

Регистрация: 03.11.2019

Сообщений: 36

14.11.2019, 21:02

 [ТС]

5

grizlik78, period = period[remainders.index(remainder):] как эту строчку без индекса переписать?



0



Эксперт С++

2378 / 1662 / 279

Регистрация: 29.05.2011

Сообщений: 3,395

14.11.2019, 21:05

6

Реализовать циклом. index() возвращает индекс первого вхождения заданного элемента в список. То есть в цикле надо перебирать элементы списка, пока не встретится заданный. Его номер в списке и есть искомый индекс.



0



Snaces

0 / 0 / 0

Регистрация: 03.11.2019

Сообщений: 36

14.11.2019, 21:14

 [ТС]

7

grizlik78,
переписал вот так вроде: Но выводит 006 вместо 6 и 009 вместо 09. Как исправить?

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
n = int(input())
 
remainders = []
period = ""
remainder = 1
 
while not (remainder in remainders):
    remainders.append(remainder)
    period += str(remainder // n)
    remainder = (remainder % n) * 10
 
for i in remainders:
    if i == remainder:
        break
 
print(period)



0



grizlik78

Эксперт С++

2378 / 1662 / 279

Регистрация: 29.05.2011

Сообщений: 3,395

14.11.2019, 21:29

8

Это потому, что надо найти номер элемента, а не там элемент. А потом ещё и использовать его.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
n = int(input())
 
remainders = []
period = ""
remainder = 1
 
while not (remainder in remainders):
    remainders.append(remainder)
    period += str(remainder // n)
    remainder = (remainder % n) * 10
 
start_pos = 0
for i in remainders:
    if i == remainder:
        break
    start_pos += 1
 
print(period[start_pos:])



1



Doing print ("repeated numbers:", t) prints the representation of the t function itself, not its output.

Here’s a repaired version of your code. I use a Python 3.6+ f-string to convert the repeating digits to a string, and add zeros to the front to make it the correct length.

def find_period(n, d):
    z = x = n * 9
    k = 1
    while z % d:
        z = z * 10 + x
        k += 1

    digits = f"{z // d:0{k}}"
    return k, digits

# Test

num, den = 1, 7
period, digits = find_period(num, den)
print('num:', num, 'den:', den, 'period:', period, 'digits:', digits)

num, den = 1, 17
period, digits = find_period(num, den)
print('num:', num, 'den:', den, 'period:', period, 'digits:', digits)

output

num: 1 den: 7 period: 6 digits: 142857
num: 1 den: 17 period: 16 digits: 0588235294117647

This line may be a bit mysterious:

f"{z // d:0{k}}"

It says: Find the largest integer less than or equal to z divided by d, convert it to a string, and pad it on the left with zeroes (if necessary) to give it a length of k.


As Goyo points out in the comments, this algorithm is not perfect. It gets stuck in a loop if the decimal contains any non-repeating part, that is, if the denominator has any factors of 2 or 5. See if you can figure out a way to deal with that.

Я хочу сделать программу на Python (3.6.5), которая говорит, например, длину. 1/7 . Выходные данные должны быть для этого примера примерно такими: «длина: 6, повторяющиеся числа: 142857». Я получил это до сих пор:

n = int(input("numerator: "))
d = int(input("denominator: "))

def t(n, d):
    x = n * 9
    z = x
    k = 1
    while z % d:
        z = z * 10 + x
        k += 1
        print ("length:", k)
        print ("repeated numbers:", t)

    return k, z / d

t(n, d)

2 ответа

Лучший ответ

Выполнение print ("repeated numbers:", t) печатает представление самой функции t, а не ее вывод.

Вот исправленная версия вашего кода. Я использую строку Python 3.6+, чтобы преобразовать повторяющиеся цифры в строку, и добавляю нули к передней части, чтобы сделать ее правильной длины.

def find_period(n, d):
    z = x = n * 9
    k = 1
    while z % d:
        z = z * 10 + x
        k += 1

    digits = f"{z // d:0{k}}"
    return k, digits

# Test

num, den = 1, 7
period, digits = find_period(num, den)
print('num:', num, 'den:', den, 'period:', period, 'digits:', digits)

num, den = 1, 17
period, digits = find_period(num, den)
print('num:', num, 'den:', den, 'period:', period, 'digits:', digits)

вывод

num: 1 den: 7 period: 6 digits: 142857
num: 1 den: 17 period: 16 digits: 0588235294117647

Эта строка может быть немного загадочной:

f"{z // d:0{k}}"

В нем говорится: найдите наибольшее целое число, меньшее или равное z, разделенному на d, преобразуйте его в строку и дополните его нулями (если необходимо) слева, чтобы дать ему длину { { Х2 }} .


Как отмечает Гойо в комментариях, этот алгоритм не идеален. Он застревает в цикле, если десятичная дробь содержит какую-либо неповторяющуюся часть, то есть если знаменатель имеет какие-либо факторы 2 или 5. Посмотрите, можете ли вы найти способ справиться с этим.


2

PM 2Ring
18 Сен 2018 в 13:37

Это моя реализация на Python https://www.geeksforgeeks.org/find-recurring -последовательность-фракция /

def fraction_to_decimal(numerator, denominator):
    """ This function returns repeating sequence of a fraction.
        If repeating sequence doesn't exits, then returns empty string """

    # Create a map to store already seen remainders
    # remainder is used as key and its position in
    # result is stored as value. Note that we need
    # position for cases like 1/6.  In this case,
    # the recurring sequence doesn't start from first
    # remainder.
    result = ""
    mapping = {}

    # Find first remainder
    remainder = numerator % denominator

    # Keep finding remainder until either remainder
    # becomes 0 or repeats
    while remainder != 0 and remainder not in mapping:

        # Store this remainder
        mapping[remainder] = len(result)

        # Multiply remainder with 10
        remainder = remainder * 10

        # Append remainder / denominator to result
        result_part = int(remainder / denominator)
        result += str(result_part)
        # print(f"Result: {result}")

        # Update remainder
        remainder = remainder % denominator
        # print(f"Map: {mapping}")

    return result

if __name__ == '__main__':
    result = fraction_to_decimal(1, 7)
    if result == "":
        print("No recurring sequence")
    else:
        print(f"nLenght of recurring sequence: {len(result)}")
        print(f"nRecurring sequence is {result}n")


1

gcurse
31 Июл 2020 в 16:58

В этом листке мы реализуем класс рациональных чисел подобно тому, что уже есть в стандартной библиотеке питона.
Только мы реализуем не все его возможности, а достаточную для разумной работы часть.
Тем самым мы научимся перегружать часть возможных операторов.
А после этого прикрутим к нашим рациональным числам новые фичи.

Итак, рациональное число.
Очевидно, что внутри нужно хранить целые числа — числитель и знаменатель.
Это будут внутренние атрибуты.
Чтобы перегрузить стандартные
операторы, нужно определить внутри класса «волшебные» (magic) функции (вернее, методы).
Они все имеют вид __ZZZZ__, то есть окружены двойными подчёркиваниями.
Все встроенные в питон методы с таким именем — «волшебные», они используются при арифметических операциях, сравнениях, приведении типов,
итерации и т.д.
Ничего не мешает создать атрибут или метод с подобным именем, только он уже не будет «волшебным».
Поэтому использовать такие имена не принято.

Вычитание: __sub__, __rsub__ и __isub__, в чём разница?

Оказывается, для переопределения вычитания есть целых три магических метода: __sub__, __rsub__ и __isub__.
Работает это следующим образом.

Для удобства введём обозначение: fr, fr1, fr2 — это будут рациональные числа, экземпляры нашего
нового класса Fraction.
Переменные m, n и т.п. — это строго целые числа.
Пусть у нас есть такой код:

class Fraction:
    ...
    def __sub__(self, other):
        ...
    def __rsub__(self, other):
        ...

fr1 = Fraction(1, 3)
fr2 = Fraction(3, 4)
n = 5
fr3 = fr1 - fr2  # На самом деле fr3 = Fraction.__sub__(fr1, fr2)
fr4 = fr1 - n    # На самом деле fr4 = Fraction.__sub__(fr1, n)
fr5 = n - fr2    # На самом деле fr5 = Fraction.__rsub__(fr2, n)

Строка fr1 - fr2 на самом деле превращается в
сначала в fr1.__sub__(fr2), а затем — в Fraction.__sub__(fr1, fr2).

Строка fr1 - n сначала превращается в
fr1.__sub__(n), а затем — в Fraction.__sub__(fr1, n).
Здесь вроде бы никаких отличий, только вторым параметром в метод __sub__ придёт целое цисло, а не рациональное.

А вот с n - fr2 более хитрая магия.
Подобно прошлому разу это превращается в n.__sub__(fr2).
Тип переменной n — это int, поэтому дальше это превращается в
int.__sub__(fr1, n).
Но тот метод __sub__, что реализован для целых чисел, ничего не знает про наши новые рациональные.
Он не знает, где там числитель и знаменатель, и даже не знает, что эта штука вообще по смыслу число.
Поэтому вместо разности возвращается специальная константа NotImplemented.
В этом случае питон понимает, что левый операнд (целое число) не умеет вычитать из себя правый операнд (рациональное).
Тогда он обращается ко второму операнду: «Эй, вычти себя из целого, он говорит, что сам не умеет».
В результате происходит вызов fr2.__rsub__(n), который в свою очередь превращается в Fraction.__rsub__(fr2, n).

То есть если целые числа не умеют вычитать из себя наши новые рациональные (а они, конечно же не умеют, откуда им?), то мы сами должны
научить наши новые рациональные числа вычитать себя из целых (и из любых других типов, если нам это надо).
И это самое «научить» реализуется в магических __rZZZ__ методах.

А с __isub__ всё гораздо проще.
Этот метод вызывается, когда мы пишем fr1 -= n.
Если этот метод в классе не реализован, то код fr1 -= n интерпретируется просто как fr1 = fr1 - n,
то есть используя «обычный» __sub__.

Список операторов, которые мы перегрузим в этом листке

Полный список волшенбных методов можно найти в документации (их довольно много на все случаи жизни): http://docs.python
.org/py3k/reference/datamodel.html.

Далее идут только те методы, которые нам в этом листке понадобятся.
Для удобства введём обозначение: fr — это рациональные числа, экземпляры нашего
нового класса Fraction.
Переменные n — это строго целые числа.

Как выглядит в коде Что на самом деле вызывается Комментарий
Арифметические операторы
Сложение
fr + n Fraction.__add__(fr, n)
n + fr int.__add__(n, fr) -> NotImplemented -> Fraction.__radd__(fr, n)
Вычитание
fr - n Fraction.__sub__(fr, n)
n - fr int.__sub__(n, fr) -> NotImplemented -> Fraction.__rsub__(fr, n)
Умножение
fr * n Fraction.__mul__(fr, n)
n * fr int.__mul__(n, fr) -> NotImplemented -> Fraction.__rmul__(fr, n)
Деление
fr / n Fraction.__truediv__(fr, n)
n / fr int.__truediv__(n, fr) -> NotImplemented -> Fraction.__rtruediv__(fr, n)
Отрицание, модуль
+fr Fraction.__pos__(fr)
-fr Fraction.__neg__(fr)
abs(fr) Fraction.__abs__(fr)
Операторы сравнения
fr < n Fraction.__lt__(fr, n) lt = Less Than
n < fr int.__lt__(n, fr) -> NotImplemented -> Fraction.__gt__(fr, n) n < fr <=> fr > n
fr > n Fraction.__gt__(fr, n) gt = Greater Than
n > fr int.__gt__(n, fr) -> NotImplemented -> Fraction.__lt__(fr, n) n > fr <=> fr < n
fr <= n Fraction.__le__(fr, n) le = Less or Equal
n <= fr int.__le__(n, fr) -> NotImplemented -> Fraction.__ge__(fr, n) n <= fr <=> fr >= n
fr >= n Fraction.__ge__(fr, n) ge = Greater or Equal
n >= fr int.__ge__(n, fr) -> NotImplemented -> Fraction.__le__(fr, n) n >= fr <=> fr <= n
fr == n Fraction.__eq__(fr, n) eq = EQual
n == fr int.__eq__(n, fr) -> NotImplemented -> Fraction.__eq__(fr, n) n == fr <=> fr == n
fr != n Fraction.__ne__(fr, n) ne = Not Equal
n != fr int.__ne__(n, fr) -> NotImplemented -> Fraction.__ne__(fr, n) n != fr <=> fr != n
Преобразование к стандартным типам
Превращение в строку
str(fr), print(fr) Fraction.__str__(fr)
repr(fr) Fraction.__repr__(fr)

Большой и сложный пример для вдумчивого исследования

Очень рекомендуется пройти эту программу по шагам в режиме отладки, чтобы увидеть, как и что происходит.

Код примера

def obj_printer(obj, show_value=True):
    return '<{} object at {} with value {}>'.format(obj.__class__.__name__, hex(id(obj)), repr(obj) if type(obj) != DummyNumbers else obj.value if show_value else '?')

class DummyNumbers():
    """Класс для демонстрации возможностей классов
    """
    print("Эта строка будет выведена раньше всех: здесь Python начал читать, как устроен этот класс")
    def __init__(self, some_value=0):
        print("Запущен конструктор. Переданы парамеры: self={} и some_value={}".format(obj_printer(self, False), obj_printer(some_value)))
        self.value = some_value

    def __repr__(self):
        print("Запущен медот __repr__. Передан self={}".format(obj_printer(self)))
        return 'DummyNumbers({})'.format(self.value)

    def __str__(self):
        print("Запущен медот __str__. Передан self={}".format(obj_printer(self)))
        return 'Дурацкое число: {}'.format(self.value)

    def __sub__(self, other):
        print("Запущен метод __sub__ с параметрами self={}, other={}. "
              "Здесь self гарантированно является экземпляром DummyNumbers, "
              "а other может быть любым объектом.".format(obj_printer(self), obj_printer(other)))
        print("Хотят self - other")
        if type(other) in (int, float):
            return DummyNumbers(self.value - other)
        elif isinstance(other, DummyNumbers):
            return DummyNumbers(self.value - other.value)
        else:
            print("Мы сами не знаем, как вычесть такой объект")
            return NotImplemented

    def __rsub__(self, other):
        print("Запущен метод __rsub__ с параметрами self={}, other={}. "
              "Здесь self гарантированно является экземпляром DummyNumbers, "
              "а other может быть любым объектом. При этом мы из other вычитаем self".format(obj_printer(self), obj_printer(other)))
        print("Хотят other - self, но класс other не знает, как вычесть self")
        if type(other) in (int, float):
            return DummyNumbers(other - self.value)
        else:
            print("Мы сами не знаем, как можно вычитать из такого объекта")
            return NotImplemented

    def __isub__(self, other):
        print("Запущен метод __isub__ с параметрами self={}, other={}. "
              "Здесь self гарантированно является экземпляром DummyNumbers, "
              "а other может быть любым объектом.".format(obj_printer(self), obj_printer(other)))
        print("Хотят из self вычесть other и положить в self")
        if type(other) in (int, float):
            self.value -= other
            return self
        elif isinstance(other, DummyNumbers):
            self.value -= other.value
            return self
        else:
            print("Мы сами не знаем, как из себя вычесть такой объект")
            return NotImplemented

print('n' * 2, 'a = DummyNumbers()')
a = DummyNumbers()

print('n' * 2, 'b = DummyNumbers(3)')
b = DummyNumbers(0)

print('n' * 2, 'c = DummyNumbers(3)')
c = DummyNumbers(3.3)

print('n' * 2, 'd = a - b')
d = a - b

print('n' * 2, 'e = b - 5')
e = b - 5

print('n' * 2, 'f = 3.3 - c')
f = 3.3 - c

print('n' * 2, 'c -= b')
c -= b

print('n' * 2, 'd -= 1.79')
d -= 1.79

print('n' * 2, 'q = 7, q -= b')
q = 7
q -= b

print('n' * 2, 'print(a, b, c, d, e, f)')
print(a, b, c, d, e, f)

print('n' * 2, "g = 'a' - a")
try:
    g = 'a' - a
except TypeError as e:
    print(e)

print('n' * 2, "g = a - 'b'")
try:
    g = a - 'b'
except TypeError as e:
    print(e)

print('n' * 2, "a -= 'q'")
try:
    a -= 'q'
except TypeError as e:
    print(e)

print('n' * 2, "q = 'q', q -= a")
try:
    q = 'q'
    q -= a
except TypeError as e:
    print(e)

Ввод-вывод и тестирование

Во всех задачах на доработку методов класса тестирование производится следующим образом:
вашей программе на вход передаётся тест, состоящий из последовательность питоновских команд, который нужно исполнить при помощи функции exec.
Сделать это удобнее всего одним из двух способов:

"""Описание класса"""

import sys
exec(sys.stdin.read())

или

"""Описание класса"""

exec(open('input.txt').read())

В первом случае ввод производится с клавиатуры (не забудьте про Ctrl+D для завершения ввода), но плохо работает отладка (debug).
Во втором случае ввод производится из файла.

В задачах A-F каждая следующая задача содержит тесты всех предыдущих.

A: Реализация методов __init__ и __str__.

Метод __init__ может принимать на вход пару целых чисел, второе из которых не равно нулю,
одно число или вообще не принимать никаких аргументов.

∙ 2 аргумента — числитель и знаменатель;

∙ 1 аргумент — числитель, знаменатель равен 1;

∙ без аргументов — числитель равен 0, знаменатель равен 1.

Метод __str__ должен возвращать строковое представление дроби в виде, показанном в тестах.

print(Fraction())
print(Fraction(179))
print(Fraction(2, 4))
print(Fraction(30, -90))
print(Fraction(8, 2))

0
179
1/2
-1/3
4

B: Реализация арифметических операций — сложение и унарный плюс (__add__, __radd__, __pos__)

Рациональные числа должны поддерживать сложения друг с другом и с целыми числами.

a = Fraction(2, 4)
b = Fraction(30, -90)
c = Fraction(3, 7)
print(a + b)
print(a + b + c + 1)
c += (+a + b)
print(c)
print(1 + a)

1/6
67/42
25/42
3/2

C: Реализация арифметических операций — вычитание и унарный минус (__sub__, __rsub__, __neg__)

a = Fraction(2, 4)
b = Fraction(30, -90)
c = Fraction(3, 7)
print(a – b)
print(-a – b – c – 2)
a -= b + c
print(a)
print(1 – c)

5/6
-109/42
17/42
4/7

D: Реализация арифметических операций — умножение (__mul__, __rmul__)

a = Fraction(1, 2)
b = Fraction(3, -7)
c = Fraction(1, 5)
print(a * b)
c *= a + b
print(c)
print(3 * a)

-3/14
1/70
3/2

E: Реализация арифметических операций — деление (__truediv__, __rtruediv__)

a = Fraction(1, 2)
b = Fraction(3, -7)
c = Fraction(1, 5)
print(a / Fraction(2, 3))
b /= c / a
print(b)
print(4 / Fraction(3, -7))

3/4
-15/14
-28/3

F: Реализация логических операций — сравнения

(==, !=, <, <=, >, >=, соответственно __eq__, __ne__, __lt__, __le__, __gt__, __ge__)

a = Fraction(2, 5)
b = Fraction(5, 12)
c = Fraction(3, 7)
d = Fraction(1, 35)
print(a > b)
print(a != c)
print(a + d == c)
print(b >= c)
print(c < a)
print(c <= a + b)
print(1 < a)

False
True
True
False
False
True
False

Используем реализацию рациональных чисел для решения задач

В следующих задачах используйте вашу реализацию рациональных чисел.

G: Ближайшая аликвотная дробь

По данной дроби, не превосходящей $1$, найдите максимальную дробь с числителем, равным $1$, не превосходящей данную.

На вход программе подаётся строка вида A/B, где A и B — натуральные числа, десятичная запись которых содержит не более $100$ знаков.

Требуется вывести дробь вида 1/С, где $dfrac{1}{C}$ — максимальная дробь с числителем, равным $1$, такая что $dfrac{1}{C}leqslantdfrac{A}{B}$.

H: Египетские дроби

Разложением дроби на сумму египетских дробей называется представление данной дроби в ввиде суммы дробей с числителем равным $1$ и разными знаменателями (дроби с числителем равным $1$ ещё называют аликвотными дробями).

Существует несколько алгоритмов разложения данной дроби на сумму египетских дробей. Намёк на один из них — предыдущая задача.

Дана дробь, не превосходящая $1$. Найти разложение данной дроби на сумму египетских дробей и вывести это разложение (см. примеры). Если разложений существует несколько, вывести любое.

На вход программе подаётся строка в формате, описанном в задаче G.

Программа должна вывести выражение — сумму различных аликвотных дробей или одну дробь, если заданная дробь является аликвотной. Значение выведенного выражения должна быть равно данной дроби.

5/121

1/25+1/757+1/763309+1/873960180913+1/1527612795642093418846225

Цепные дроби

Определение: цепная (или непрерывная) дробь (continued fraction)— это конечное или бесконечное
выражение вида:
$$[a_0;a_1,a_2,dots]=a_0+dfrac{1}{a_1+dfrac{1}{a_2+dfrac{1}{a_3+dots}}}$$
где $a_0$ — целое число, остальные $a_i$ — натуральные числа, причём если дробь конечная, то последнее значение отлично от единицы.
Число представляется конечной цепной дробью тогда и только тогда, когда оно рационально.

Декоратор @staticmethod для методов, которым не нужен экземпляр класса

Сейчас мы добавим нашим дробям возможность превращения в цепную или периодическую десятичную дробь и обратно.
Начнём с конструирования рационального числа из цепной дроби.

Добавим метод from_continued в класс Fraction, который по массиву или кортежу целых чисел — элементов
цепной дроби — будет создавать дробь.
Работать это должно так:

class Fraction:
    ...
    def from_continued(terms):
        ...
        return Fraction(p, q)

x = Fraction.from_continued([1, 1, 2])  # 5/3
y = Fraction.from_continued([0, 2, 4, 8, 16])  # 532/1193

Обратите внимание, здесь внутри метода from_continued нам не нужен self — экземпляр класса.
При вызове как в примере выше он и не будет передан.
Но этот метод можно вызвать и так:

>>> x = Fraction(1, 2)
>>> y = x.from_continued([1, 1, 2])
TypeError: from_continued() takes 1 positional argument but 2 were given

Нужно дать знать питону, что экземпляр класса нам никогда не потребуется.
Для этого перед определением метода нужно добавить декоратор @staticmethod.
Вот так:

class Fraction:
    ...
    @staticmethod
    def from_continued(terms):
        ...
        return Fraction(p, q)

Декоратор @classmethod

На самом деле в таком сценарии нужно писать так:

class Fraction:
    ...
    @classmethod
    def from_continued(cls, terms):
        ...
        return cls(p, q)

Это всё очень похоже на @staticmethod, только первым параметром вне зависимости от вызова будет передан сам класс.
Это важно для правильной работы при использовании наследования.
В контексте данного листка это всё неважно.

I: Получение значения дроби по её разложению в цепную дробь

Добавьте метод from_continued в класс Fraction, который по массиву или кортежу целых чисел — элементов
цепной дроби — будет создавать дробь.

print(Fraction.from_continued([1, 1, 2]))

5/3

print(Fraction.from_continued([3]))
print(Fraction.from_continued([1, 2, 3]))
print(Fraction.from_continued([0, 2, 4, 8, 16]))
print(Fraction(1, 3) + Fraction.from_continued([1, 1, 2]))

3
10/7
532/1193
2

J: Разложение данной дроби в цепную дробь

Добавьте метод to_continued в класс Fraction,
который возвращает массив, представляющие собой разложение данной дроби в цепную дробь.

print(Fraction(5, 3).to_continued())

[1, 1, 2]

print(Fraction(3).to_continued())
print(Fraction(10, 7).to_continued())

[3]
[1, 2, 3]

print(Fraction(532, 1193).to_continued())
print(Fraction(-7, 3).to_continued())
print((1 + 1 / (2 + 1 / (2 + 1 / (2 + 1 / (2 + Fraction(1, 2)))))).to_continued())

[0, 2, 4, 8, 16]
[-3, 1, 2]
[1, 2, 2, 2, 2, 2]

K: Ближайшая дробь

По данной дроби $frac{A}{B}~(A, B < 10^{10})$ найти ближайшую к ней дробь со знаменателем, не превышающим данное число $Q~(Q < 20000)$, где $Q < B$.
Если для данной дроби существует несколько дробей, равноудалённых от неё — выведите дробь с наименьшим знаменателем.
Реализуйте это в виде метода limit_denominator.

print(Fraction(10, 23).limit_denominator(22))

7/16

print(Fraction(16, 23).limit_denominator(22))
print(Fraction(13, 57).limit_denominator(10))
print(Fraction(123, 1000).limit_denominator(100))

9/13
2/9
8/65

L: Получение по периодическому представлению дроби её значения

Дана строка, содержащая десятичную запись дроби. Либо дробь — целое число, либо обязательно содержит ровно одну точку.
Слева от точки — запись целого числа.
Справа от точки последовательность цифр от $0$ до $9$, при этом возможно какой-то непустой суффикс этой последовательности взят в круглые скобки.

Требуется вычислить и вывести значение соответствующей несократимой дроби.

Реализуйте это в виде метода from_repeating (по-английски периодическая дробь — repeating decimal).

print(Fraction.from_repeating(‘1.41(6)’))

17/12

print(Fraction.from_repeating(‘0.(0588235294117647)’))
print(Fraction.from_repeating(‘0.(629)’))
print(Fraction.from_repeating(‘0.25’))

1/17
17/27
1/4

M: Получение по значению дроби её периодического представления

Дана дробь $A/B~(A,B < 10000)$.
Требуется вывести её представление в виде конечной десятичной или бесконечной периодической дроби.

Обратите внимание, что дроби допускают различные способы записи. Проверьте, что соблюдены следующие правила:

  • Конечная десятичная дробь не содержит незначащих нулей. $dfrac{1}{8}=0.12500=0.125$
  • Бесконечная периодическая дробь записана без предпериода, если это возможно. Например, $dfrac{1231}{9999}=0.123(1123)=0.(1231)$
  • Если предпериод есть, его длина минимальна: $dfrac{211}{990}=0.21(31)=0.2(13)$
  • Длина периода наименьшая из возможных: $dfrac{1}{3}=0.(33)=0.(3)$

Реализуйте это в виде метода to_repeating.

print(Fraction(17, 12).to_repeating())

1.41(6)

print(Fraction(1, 17).to_repeating())
print(Fraction(17, 27).to_repeating())
print(Fraction(1, 4).to_repeating())

0.(0588235294117647)
0.(629)
0.25

N★: Ближайшая дробь (быстрый алгоритм)

По данной дроби $frac{A}{B}~(A, B < 10^{100})$ найти ближайшую к ней дробь со знаменателем, не превышающим данное число $Q$, где $Q < B$.
Если для данной дроби существует несколько дробей, равноудалённых от неё — выведите дробь с наименьшим знаменателем.

Эта задача в точности совпадает с задачей K, отличаясь только ограничениями на величину числителя и знаменателя
данной дроби.

Литература по теме:

  • В.В. Прасолов «Задачи по алгебре, арифметике и анализу»
  • И.Н. Сергеев, С.Н. Олехник, С.Б. Гашков «Примени математику»
  • Г. Дэвенпорт «Высшая арифметика»
  • А.Я. Хинчин «Цепные дроби»
  • В.И. Арнольд «Цепные дроби»
  • Wikipedia

O: Игра с калькулятором

У вас есть калькулятор, который умеет выполнять арифетические операции (сложение, вычитание, умножение и деление). Результат деления целых чисел (в случае, когда он не является целым числом) калькулятор умеет показывать вам с точностью до, скажем, первых $50$ десятичных разрядов.

Представим себе следующую игру. Вы можете выбрать один из возможных вариантов действий:

  • выбираете два случайных числа от $1$ до $100000$ и делите одно на другое. Получаете ответ в виде дроби, и выписываете первые $50$ десятичных разрядов его дробной части.
  • водите пальцем по кнопкам калькулятора и получаете случайную последовательность из $50$ цифр.

Ваша задача: написать программу, которая в данных условиях сумеет определить по последовательности $50$-разрядных чисел, какой из способов был использован для её получения. Если число получено при помощи деления, выведите RATIONAL, иначе выведите RANDOM.

Тесты в этой задаче закрытые.

Литература по теме приведена в предыдущей задаче, а кроме того можно почитать, например, замечательную книжку «Математический дивертисмент» Сергея Табачникова и Дмитрия Фукса.

81504858796678001868515099327620295960919576801285
04098472842529894827834605964558420976804495029534
65620886155843687447027212233783564459993147350008
79295424616572769488202619879798409853758032416804
71368110823794816367183940729755459969648507089869
07230935482661632464220914285636669261174201759061
43310946362920969724658715119924460828397453981816
90649125634120798608004383559140501051799143861756
79485406521331383752787840945353627149102220745097
05471764553143675247574915667388590104261979378050
24717702242571855712176717634740996700813924196593
21312930451324098918111530306951235568388698964419
57883145363408521303258145363408521303258145363408
01343024319940693740495976222241919349472954757105
48801448623934179631989798866771907139267742835221
74348181090299672014058440458666709321435862483290
67249820645206154629459022682671783225975622784159
64675440512886031049490848581904652357555031463319
10787289277703996105308724182035123346197096394835
09287249830099443835730433697174796466068431783193

RANDOM
RATIONAL
RATIONAL
RATIONAL
RATIONAL
RANDOM
RANDOM
RANDOM
RANDOM
RANDOM
RANDOM
RATIONAL
RATIONAL
RATIONAL
RANDOM
RANDOM
RANDOM
RANDOM
RATIONAL
RATIONAL

Первая версия требует, чтобы числитель и знаменатель были экземплярами чисел. numbers.Rational и возвращает новый экземпляр Fraction со значением numerator/denominator . Если знаменатель равен 0 , возникает ZeroDivisionError . Вторая версия требует, чтобы other_fraction был экземпляром numbers.Rational и возвращал экземпляр Fraction с тем же значением. Следующие две версии принимают либо число с float , либо экземпляр decimal.Decimal и возвращают Fraction экземпляр с точно таким же значением. Обратите внимание, что из-за обычных проблем с двоичными числами с плавающей запятой (см. Арифметика с плавающей запятой: проблемы и ограничения ) аргумент Fraction(1.1) не точно равен 11/10, поэтому Fraction(1.1) не возвращает Fraction(11, 10) как и следовало ожидать. (Но см. документацию по limit_denominator() ниже.) Последняя версия конструктора ожидает строку или экземпляр Unicode. Обычная форма для этого экземпляра:

[sign] numerator ['/' denominator]

где необязательный sign может быть «+» или «-», а numerator и denominator (если он присутствует) представляют собой строки десятичных цифр (символы подчеркивания могут использоваться для разделения цифр, как и в случае целочисленных литералов в коде). Кроме того, любая строка, представляющая конечное значение и принятая конструктором float , также принимается конструктором Fraction . В любой форме входная строка также может иметь начальные и/или конечные пробелы. Вот некоторые примеры:

>>> from fractions import Fraction
>>> Fraction(16, -10)
Fraction(-8, 5)
>>> Fraction(123)
Fraction(123, 1)
>>> Fraction()
Fraction(0, 1)
>>> Fraction('3/7')
Fraction(3, 7)
>>> Fraction(' -3/7 ')
Fraction(-3, 7)
>>> Fraction('1.414213 tn')
Fraction(1414213, 1000000)
>>> Fraction('-.125')
Fraction(-1, 8)
>>> Fraction('7e-6')
Fraction(7, 1000000)
>>> Fraction(2.25)
Fraction(9, 4)
>>> Fraction(1.1)
Fraction(2476979795053773, 2251799813685248)
>>> from decimal import Decimal
>>> Fraction(Decimal('1.1'))
Fraction(11, 10)

Класс Fraction наследуется от абстрактного базового класса numbers.Rational и реализует все методы и операции этого класса. Экземпляры Fraction являются хешируемыми и должны рассматриваться как неизменяемые. Кроме того, Fraction имеет следующие свойства и методы:

Изменено в версии 3.2: Конструктор Fraction теперь принимает экземпляры float и decimal.Decimal .

Изменено в версии 3.9: math.gcd() теперь используется для нормализации числителя и знаменателя . math.gcd() всегда возвращает тип int . Раньше тип НОД зависел от числителя и знаменателя .

Изменено в версии 3.11: Подчеркивание теперь разрешено при создании экземпляра Fraction из строки в соответствии с правилами PEP 515 .

Изменено в версии 3.11: Fraction теперь реализует __int__ , чтобы удовлетворить проверки экземпляра typing.SupportsInt .

numerator

Числитель фракции в самом нижнем семестре.

denominator

Знаменатель фракции в нижнем семестре.

as_integer_ratio()

Вернуть кортеж из двух целых чисел,соотношение которых равно дроби и имеет положительный знаменатель.

Новинка в версии 3.8.

classmethod from_float(flt)

Альтернативный конструктор, который принимает только экземпляры float или numbers.Integral . Помните, что значение Fraction.from_float(0.3) не совпадает с значением Fraction(3, 10) .

Note

Начиная с Python 3.2, вы также можете создавать экземпляр Fraction непосредственно из числа с float .

classmethod from_decimal(dec)

Альтернативный конструктор, который принимает только экземпляры decimal.Decimal или numbers.Integral .

Note

Начиная с Python 3.2, вы также можете создать экземпляр Fraction непосредственно из экземпляра decimal.Decimal .

limit_denominator(max_denominator=1000000)

Находит и возвращает ближайшую к self Fraction , знаменатель которой не превышает max_denominator. Этот метод полезен для поиска рациональных приближений к заданному числу с плавающей запятой:

>>> from fractions import Fraction
>>> Fraction('3.1415926535897932').limit_denominator(1000)
Fraction(355, 113)

или для восстановления рационального числа,представленного в виде float:

>>> from math import pi, cos
>>> Fraction(cos(pi/3))
Fraction(4503599627370497, 9007199254740992)
>>> Fraction(cos(pi/3)).limit_denominator()
Fraction(1, 2)
>>> Fraction(1.1).limit_denominator()
Fraction(11, 10)
__floor__()

Возвращает наибольшее значение int <= self . К этому методу также можно получить доступ через math.floor() :

>>> from math import floor
>>> floor(Fraction(355, 113))
3
__ceil__()

Возвращает наименьшее значение int >= self . К этому методу также можно получить доступ через math.ceil() .

__round__()
__round__(ndigits)

Первая версия возвращает ближайшее int к self , округляя половину до четного. Вторая версия округляет self до ближайшего кратного Fraction(1, 10**ndigits) (логически, если ndigits отрицательное), снова округляя половину в сторону четности . К этому методу также можно получить доступ через функцию round() .

Добавить комментарий