130 lines
4.0 KiB
Python
130 lines
4.0 KiB
Python
from decimal import Decimal, getcontext
|
|
|
|
# увеличиваем точность для больших чисел до 50 значащих цифр в вычислениях
|
|
getcontext().prec = 50
|
|
|
|
|
|
class Fraction:
|
|
def __init__(self, numerator, denominator):
|
|
self._numerator = None
|
|
self._denominator = None
|
|
|
|
self.set_numerator(numerator)
|
|
self.set_denominator(denominator)
|
|
|
|
self.validate_proper_fraction()
|
|
|
|
# ------------------------
|
|
# УСТАНОВКА ЧИСЛИТЕЛЯ
|
|
def set_numerator(self, numerator):
|
|
self._numerator = self.validate_numerator(numerator)
|
|
|
|
# ------------------------
|
|
# УСТАНОВКА ЗНАМЕНАТЕЛЯ
|
|
def set_denominator(self, denominator):
|
|
self._denominator = self.validate_denominator(denominator)
|
|
|
|
@staticmethod
|
|
def validate_numerator(numerator) -> int:
|
|
try:
|
|
num = Decimal(numerator)
|
|
except:
|
|
raise ValueError("Числитель должен быть числом")
|
|
|
|
if num != num.to_integral_value():
|
|
raise ValueError("Числитель должен быть целым числом")
|
|
|
|
num = int(num)
|
|
|
|
if num <= 0:
|
|
raise ValueError("Числитель должен быть положительным")
|
|
|
|
return num
|
|
|
|
@staticmethod
|
|
def validate_denominator(denominator) -> int:
|
|
try:
|
|
den = Decimal(denominator)
|
|
except:
|
|
raise ValueError("Знаменатель должен быть числом")
|
|
|
|
if den != den.to_integral_value():
|
|
raise ValueError("Знаменатель должен быть целым числом")
|
|
|
|
den = int(den)
|
|
|
|
if den <= 0:
|
|
raise ValueError("Знаменатель должен быть положительным")
|
|
|
|
return den
|
|
|
|
# ------------------------
|
|
# ПРОВЕРКА ПРАВИЛЬНОЙ ДРОБИ
|
|
def validate_proper_fraction(self):
|
|
if self._numerator >= self._denominator:
|
|
raise ValueError(
|
|
"Это не правильная дробь (числитель должен быть меньше знаменателя)"
|
|
)
|
|
|
|
# ------------------------
|
|
# МЕТОД №1: В ПРОЦЕНТЫ (всегда 2 знака)
|
|
def to_percent(self) -> str:
|
|
value = (Decimal(self._numerator) / Decimal(self._denominator)) * Decimal(100)
|
|
return f"{value:.2f}"
|
|
|
|
# ------------------------
|
|
# МЕТОД №2: СУММА ЦИФР ЗНАМЕНАТЕЛЯ
|
|
def sum_digits_denominator(self) -> int:
|
|
return sum(int(d) for d in str(self._denominator))
|
|
|
|
# ------------------------
|
|
# СТРОКА ИНФОРМАЦИИ
|
|
def info(self) -> str:
|
|
return (
|
|
f"Дробь: {self._numerator}/{self._denominator} | "
|
|
f"Проценты: {self.to_percent()}% | "
|
|
f"Сумма цифр знаменателя: {self.sum_digits_denominator()}"
|
|
)
|
|
|
|
|
|
# ------------------------
|
|
# ВВОД С ПОДДЕРЖКОЙ 1e32
|
|
def input_number(prompt: str):
|
|
while True:
|
|
value = input(prompt).strip()
|
|
try:
|
|
Decimal(value) # проверка валидности
|
|
return value
|
|
except:
|
|
print("Ошибка: введите число (поддерживается формат 1e32)")
|
|
|
|
|
|
def input_fraction() -> Fraction:
|
|
while True:
|
|
try:
|
|
num = input_number("Введите числитель: ")
|
|
den = input_number("Введите знаменатель: ")
|
|
return Fraction(num, den)
|
|
except ValueError as e:
|
|
print("Ошибка:", e)
|
|
|
|
|
|
# ------------------------
|
|
def main():
|
|
print("Ввод дроби с клавиатуры:")
|
|
frac_input = input_fraction()
|
|
|
|
# Константы
|
|
frac1 = Fraction(1, 2)
|
|
frac2 = Fraction("32", "540")
|
|
|
|
fractions = [frac_input, frac1, frac2]
|
|
|
|
print("\nРезультаты:")
|
|
for f in fractions:
|
|
print(f.info())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|