This commit is contained in:
2025-11-08 11:16:24 +05:00
parent 81c60f2c70
commit 760fb43e62
16 changed files with 2798 additions and 257 deletions

View File

@@ -0,0 +1,537 @@
"""
Модуль для пошагового решения задач с системами счисления (2, 8, 16, n-ричные)
Алгоритм работает аналогично Photomath - показывает каждый шаг решения
"""
from typing import List, Tuple, Dict
from enum import Enum
class Operation(Enum):
"""Типы операций"""
ADDITION = "сложение"
SUBTRACTION = "вычитание"
class NumberSystem(Enum):
"""Поддерживаемые системы счисления"""
BINARY = 2
OCTAL = 8
DECIMAL = 10
HEXADECIMAL = 16
class Step:
"""Класс для представления одного шага решения"""
def __init__(self, title: str, description: str, visual: str = "", result: str = ""):
self.title = title # Название шага
self.description = description # Описание что делается
self.visual = visual # Визуальное представление
self.result = result # Результат этого шага
def __str__(self):
output = f"\n{'='*60}\n"
output += f"ШАГ: {self.title}\n"
output += f"{'='*60}\n"
output += f"{self.description}\n"
if self.visual:
output += f"\n{self.visual}\n"
if self.result:
output += f"\n➤ Результат: {self.result}\n"
return output
class StepByStepSolver:
"""
Класс для пошагового решения задач с системами счисления
"""
def __init__(self, base: int = 10, digits: str = None):
"""
Инициализация решателя
Args:
base: основание системы счисления (2, 8, 10, 16 или любое n)
digits: строка с символами для представления цифр (по умолчанию 0-9A-Z)
"""
self.base = base
self.steps: List[Step] = []
# Используем пользовательский набор символов или стандартный
if digits is not None:
self.digits = digits
else:
self.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def clear_steps(self):
"""Очистить все шаги решения"""
self.steps = []
def get_system_name(self) -> str:
"""Получить название системы счисления"""
names = {
2: "двоичная",
8: "восьмеричная",
10: "десятичная",
16: "шестнадцатеричная"
}
return names.get(self.base, f"{self.base}-ричная")
def validate_number(self, number: str) -> bool:
"""
Проверка корректности числа в данной системе счисления
Args:
number: строка с числом
Returns:
True если число корректно, False иначе
"""
number = number.upper().replace('-', '')
valid_digits = self.digits[:self.base]
return all(c in valid_digits for c in number)
def to_decimal(self, number: str) -> int:
"""
Преобразование числа из n-ричной системы в десятичную
Args:
number: число в n-ричной системе
Returns:
число в десятичной системе
"""
is_negative = number.startswith('-')
number = number.replace('-', '').upper()
result = 0
for i, digit in enumerate(reversed(number)):
digit_value = self.digits.index(digit)
result += digit_value * (self.base ** i)
return -result if is_negative else result
def from_decimal(self, number: int) -> str:
"""
Преобразование из десятичной системы в n-ричную
Args:
number: число в десятичной системе
Returns:
число в n-ричной системе
"""
if number == 0:
return "0"
is_negative = number < 0
number = abs(number)
result = ""
while number > 0:
result = self.digits[number % self.base] + result
number //= self.base
return ("-" + result) if is_negative else result
def convert_with_steps(self, number: str, target_base: int) -> List[Step]:
"""
Преобразование числа в другую систему счисления с пошаговым объяснением
Args:
number: исходное число
target_base: целевая система счисления
Returns:
список шагов решения
"""
steps = []
is_negative = number.startswith('-')
number = number.replace('-', '').upper()
# Шаг 1: Исходные данные
step1 = Step(
"Исходные данные",
f"Необходимо преобразовать число {number} из {self.get_system_name()} " +
f"({self.base}-ричной) системы в {target_base}-ричную систему",
f"Исходное число: {'-' if is_negative else ''}{number}{self.base}"
)
steps.append(step1)
# Шаг 2: Перевод в десятичную систему (если нужно)
if self.base != 10:
decimal_value = 0
calculation = []
for i, digit in enumerate(reversed(number)):
digit_value = self.digits.index(digit)
power = self.base ** i
term_value = digit_value * power
decimal_value += term_value
calculation.append(f"{digit}×{self.base}^{i} = {digit_value}×{power} = {term_value}")
visual = "\n".join(calculation)
visual += f"\n\nСумма: {' + '.join([str(digit_value * (self.base ** i)) for i, digit in enumerate(reversed(number)) for digit_value in [self.digits.index(digit)]])} = {decimal_value}"
step2 = Step(
"Перевод в десятичную систему",
f"Каждую цифру умножаем на {self.base} в степени её позиции (справа налево, начиная с 0)",
visual,
f"{decimal_value}₍₁₀₎"
)
steps.append(step2)
else:
decimal_value = int(number)
# Шаг 3: Перевод из десятичной в целевую систему (если нужно)
if target_base != 10:
divisions = []
temp = decimal_value
result_digits = []
while temp > 0:
remainder = temp % target_base
quotient = temp // target_base
result_digits.insert(0, self.digits[remainder])
divisions.append(f"{temp} ÷ {target_base} = {quotient}, остаток: {remainder} ({self.digits[remainder]})")
temp = quotient
result_number = ''.join(result_digits) if result_digits else "0"
visual = "\n".join(divisions)
visual += f"\n\nЧитаем остатки снизу вверх: {result_number}"
step3 = Step(
f"Перевод в {target_base}-ричную систему",
f"Делим число на {target_base} и записываем остатки. " +
"Читаем остатки снизу вверх",
visual,
f"{'-' if is_negative else ''}{result_number}{target_base}"
)
steps.append(step3)
final_result = ('-' if is_negative else '') + result_number
else:
final_result = str(decimal_value)
# Финальный шаг
final_step = Step(
"Итоговый результат",
f"Число {'-' if is_negative else ''}{number}{self.base}₎ = {final_result}{target_base}",
"",
f"{final_result}{target_base}"
)
steps.append(final_step)
return steps
def add_with_steps(self, num1: str, num2: str) -> List[Step]:
"""
Сложение двух чисел в n-ричной системе с пошаговым объяснением
Args:
num1: первое число
num2: второе число
Returns:
список шагов решения
"""
steps = []
# Шаг 1: Исходные данные
step1 = Step(
"Условие задачи",
f"Необходимо сложить два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления",
f"{num1}{self.base}₎ + {num2}{self.base}₎ = ?",
""
)
steps.append(step1)
# Проверка на отрицательные числа
is_neg1 = num1.startswith('-')
is_neg2 = num2.startswith('-')
num1_clean = num1.replace('-', '').upper()
num2_clean = num2.replace('-', '').upper()
# Шаг 2: Выравнивание разрядов
max_len = max(len(num1_clean), len(num2_clean))
num1_aligned = num1_clean.zfill(max_len)
num2_aligned = num2_clean.zfill(max_len)
visual = f" {num1_aligned}\n+ {num2_aligned}\n" + "-" * (max_len + 2)
step2 = Step(
"Выравнивание чисел",
f"Дополняем числа нулями слева до одинаковой длины ({max_len} разрядов)",
visual,
""
)
steps.append(step2)
# Шаг 3: Сложение в столбик
result = []
carry = 0
detailed_calc = []
for i in range(max_len - 1, -1, -1):
d1 = self.digits.index(num1_aligned[i])
d2 = self.digits.index(num2_aligned[i])
total = d1 + d2 + carry
digit_result = total % self.base
new_carry = total // self.base
result.insert(0, self.digits[digit_result])
position = max_len - i - 1
explanation = f"Позиция {position}: {num1_aligned[i]}({d1}) + {num2_aligned[i]}({d2})"
if carry > 0:
explanation += f" + перенос({carry})"
explanation += f" = {total}"
if new_carry > 0:
explanation += f" = {digit_result} (перенос {new_carry})"
else:
explanation += f" = {digit_result}"
detailed_calc.insert(0, explanation)
carry = new_carry
if carry > 0:
result.insert(0, self.digits[carry])
detailed_calc.insert(0, f"Финальный перенос: {carry}")
result_str = ''.join(result)
visual = "\n".join(detailed_calc)
visual += f"\n\nВизуализация:\n {num1_aligned}\n+ {num2_aligned}\n" + "-" * (max_len + 2) + f"\n {result_str}"
step3 = Step(
"Сложение в столбик",
f"Складываем числа справа налево, учитывая переносы. " +
f"При сумме ≥ {self.base} делим на {self.base}: остаток - результат, частное - перенос",
visual,
f"{result_str}{self.base}"
)
steps.append(step3)
# Шаг 4: Проверка через десятичную систему
dec1 = self.to_decimal(num1)
dec2 = self.to_decimal(num2)
dec_result = dec1 + dec2
step4 = Step(
"Проверка результата",
"Проверим правильность через перевод в десятичную систему",
f"{num1}{self.base}₎ = {dec1}₍₁₀₎\n" +
f"{num2}{self.base}₎ = {dec2}₍₁₀₎\n" +
f"{dec1} + {dec2} = {dec_result}\n" +
f"{dec_result}₍₁₀₎ = {result_str}{self.base}",
f"✓ Ответ верен: {result_str}{self.base}"
)
steps.append(step4)
return steps
def subtract_with_steps(self, num1: str, num2: str) -> List[Step]:
"""
Вычитание двух чисел в n-ричной системе с пошаговым объяснением
Args:
num1: уменьшаемое
num2: вычитаемое
Returns:
список шагов решения
"""
steps = []
# Шаг 1: Исходные данные
step1 = Step(
"Условие задачи",
f"Необходимо вычесть два числа в {self.get_system_name()} ({self.base}-ричной) системе счисления",
f"{num1}{self.base}₎ - {num2}{self.base}₎ = ?",
""
)
steps.append(step1)
# Определяем знак результата
dec1 = self.to_decimal(num1)
dec2 = self.to_decimal(num2)
is_negative = dec1 < dec2
# Работаем с абсолютными значениями
if is_negative:
num1, num2 = num2, num1
num1 = num1.replace('-', '')
num2 = num2.replace('-', '')
num1_clean = num1.replace('-', '').upper()
num2_clean = num2.replace('-', '').upper()
# Шаг 2: Выравнивание разрядов
max_len = max(len(num1_clean), len(num2_clean))
num1_aligned = num1_clean.zfill(max_len)
num2_aligned = num2_clean.zfill(max_len)
visual = f" {num1_aligned}\n- {num2_aligned}\n" + "-" * (max_len + 2)
step2 = Step(
"Выравнивание чисел",
f"Дополняем числа нулями слева до одинаковой длины ({max_len} разрядов)",
visual,
""
)
steps.append(step2)
# Шаг 3: Вычитание в столбик
result = []
borrow = 0
detailed_calc = []
num1_list = list(num1_aligned)
for i in range(max_len - 1, -1, -1):
d1 = self.digits.index(num1_list[i])
d2 = self.digits.index(num2_aligned[i])
# Учитываем заем
d1 -= borrow
position = max_len - i - 1
explanation = f"Позиция {position}: {num1_list[i]}({self.digits.index(num1_list[i])})"
if borrow > 0:
explanation += f" - заем({borrow})"
explanation += f" = {d1}"
explanation += f" - {num2_aligned[i]}({d2})"
if d1 < d2:
# Нужен заем
d1 += self.base
borrow = 1
explanation += f" → занимаем {self.base}, получаем {d1} - {d2} = {d1 - d2}"
else:
borrow = 0
explanation += f" = {d1 - d2}"
digit_result = d1 - d2
result.insert(0, self.digits[digit_result])
detailed_calc.insert(0, explanation)
# Убираем ведущие нули
result_str = ''.join(result).lstrip('0') or '0'
visual = "\n".join(detailed_calc)
visual += f"\n\nВизуализация:\n {num1_aligned}\n- {num2_aligned}\n" + "-" * (max_len + 2)
visual += f"\n {result_str.zfill(max_len)}"
if is_negative:
result_str = '-' + result_str
step3 = Step(
"Вычитание в столбик",
f"Вычитаем числа справа налево. " +
f"Если цифра уменьшаемого меньше вычитаемого, занимаем {self.base} из следующего разряда",
visual,
f"{result_str}{self.base}"
)
steps.append(step3)
# Шаг 4: Проверка
dec_result = dec1 - dec2
step4 = Step(
"Проверка результата",
"Проверим правильность через перевод в десятичную систему",
f"{num1}{self.base}₎ = {dec1}₍₁₀₎\n" +
f"{num2}{self.base}₎ = {dec2}₍₁₀₎\n" +
f"{dec1} - {dec2} = {dec_result}\n" +
f"{dec_result}₍₁₀₎ = {result_str}{self.base}",
f"✓ Ответ верен: {result_str}{self.base}"
)
steps.append(step4)
return steps
def solve(self, num1: str, num2: str, operation: Operation) -> List[Step]:
"""
Решить задачу с пошаговым объяснением
Args:
num1: первое число
num2: второе число
operation: тип операции (сложение/вычитание)
Returns:
список шагов решения
"""
if operation == Operation.ADDITION:
return self.add_with_steps(num1, num2)
elif operation == Operation.SUBTRACTION:
return self.subtract_with_steps(num1, num2)
else:
raise ValueError(f"Неподдерживаемая операция: {operation}")
def print_solution(self, steps: List[Step]):
"""
Вывести решение в консоль
Args:
steps: список шагов решения
"""
print("\n" + "="*60)
print("ПОШАГОВОЕ РЕШЕНИЕ")
print("="*60)
for i, step in enumerate(steps, 1):
print(f"\n{''*60}")
print(f"ШАГ {i}: {step.title}")
print(f"{''*60}")
print(f"\n{step.description}")
if step.visual:
print(f"\n{step.visual}")
if step.result:
print(f"\n➤ Результат: {step.result}")
print("\n" + "="*60)
print("РЕШЕНИЕ ЗАВЕРШЕНО")
print("="*60 + "\n")
# Пример использования
if __name__ == "__main__":
# Пример 1: Сложение в двоичной системе
print("ПРИМЕР 1: СЛОЖЕНИЕ В ДВОИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=2)
steps = solver.solve("1011", "110", Operation.ADDITION)
solver.print_solution(steps)
# Пример 2: Вычитание в восьмеричной системе
print("\n\nПРИМЕР 2: ВЫЧИТАНИЕ В ВОСЬМЕРИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=8)
steps = solver.solve("756", "237", Operation.SUBTRACTION)
solver.print_solution(steps)
# Пример 3: Сложение в шестнадцатеричной системе
print("\n\nПРИМЕР 3: СЛОЖЕНИЕ В ШЕСТНАДЦАТЕРИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=16)
steps = solver.solve("A5", "3F", Operation.ADDITION)
solver.print_solution(steps)
# Пример 4: Сложение в пятеричной системе
print("\n\nПРИМЕР 4: СЛОЖЕНИЕ В ПЯТЕРИЧНОЙ СИСТЕМЕ")
print("="*60)
solver = StepByStepSolver(base=5)
steps = solver.solve("234", "142", Operation.ADDITION)
solver.print_solution(steps)