Новая Школа - онлайн-школа подготовки к ЕГЭ
Информатика · 4 класс Задача №3616836
А
Аноним
29 мая 2026 11:27 · публичный вопрос
А
Аноним

сделай пожалуйста калькулятор для pydroid3

Ответ нейросети
29 мая 2026 11:27

Отлично! Ты попросил сделать калькулятор для Pydroid3. Так как цель — понять материал, ниже я объясню по шагам, что именно делает калькулятор, и дам готовый код, который можно просто вставить в Pydroid3 и запустить.

Что умеет этот калькулятор

  • Вычисляет арифметические выражения с операциями: сложение +, вычитание -, умножение *, деление / и возведение в степень ^.
  • Поддерживает скобки: ( … ).
  • Поддерживает десятичные числа.
  • Поддерживает унарный минус (например, -5, (-3 + 2)).
  • Безопасный альтернативный подход к eval: расчет идет через разбор выражения и постфиксную запись (обратную польскую нотацию), чтобы избежать рискованных вызовов eval.

Как работает калькулятор (пошагово, для понимания)

  1. Препроcсинг выражения
    • Убираем пробелы и преобразуем несколько форм возведения степени в единый символ ^ (например, в выражении ** превращаемось в ^).
  2. Разбор на токены
    • Разделяем строку на числа (например 12, 3.5), операторы (+, -, *, /, ^) и скобки.
  3. Преобразование в постфиксную запись (обратная польская нотация)
    • Используется алгоритм Шантинга-Ярда.
    • Сразу поддерживаем унарный минус: если минус стоит на месте, где ожидается число (в начале выражения, после скобки или после другого оператора), он трактуется как унарный минус.
    • В постфиксной записи число идёт перед операцией, например: "3 4 +".
  4. Вычисление постфиксной записи
    • С помощью стека вычисляем результат по постфиксной записи.
    • Поддерживаются все нужные операции, включая унарный минус.
  5. Результат
    • Выводится значение выражения. Если выражение неверное, выводится понятная ошибка.

Инструкция по запуску в Pydroid3

  • Открой новое пустое Python-файло в Pydroid3.
  • Скопируй сюда код ниже.
  • Выполни файл. В консоли можно вводить выражения, например: 2*(3+4), -5+2, (1+2)^3.
  • Чтобы выйти, введи exit или quit.

Готовый код (консольный калькулятор на Python)

  • Скопируй весь код ниже и сохрани как, например, calc.py, затем запусти в Pydroid3.
# Консольный калькулятор для Pydroid3
# Поддерживает: +, -, *, /, ^, скобки, десятичные числа, унарный минус

def preprocess(expr: str) -> str:
    # Убираем пробелы и преобразуем двойной звездочка в ^
    s = expr.replace(' ', '')
    s = s.replace('**', '^')
    return s

def is_number(token: str) -> bool:
    try:
        float(token)
        return True
    except ValueError:
        return False

def tokenize(s: str):
    tokens = []
    i = 0
    while i < len(s):
        c = s[i]
        if c.isdigit() or c == '.':
            j = i
            dot = 0
            while j < len(s) and (s[j].isdigit() or s[j] == '.'):
                if s[j] == '.':
                    dot += 1
                    if dot > 1:
                        break
                j += 1
            tokens.append(s[i:j])
            i = j
        elif c in '+-*/^()':
            tokens.append(c)
            i += 1
        else:
            raise ValueError(f"Недопустимый символ: '{c}'")
    return tokens

def precedence(op: str) -> int:
    if op == 'u-':  # унарный минус
        return 4
    if op == '^':
        return 3
    if op in ('*', '/'):
        return 2
    if op in ('+', '-'):
        return 1
    return 0

def associativity(op: str) -> str:
    # Сложение и умножение — левоассоциативны; ^ и унарный минус — правоассоциативны
    if op in ('^', 'u-'):
        return 'R'
    return 'L'

def to_rpn(tokens):
    out = []
    stack = []
    # prev держит тип предыдущего токена: 'NUM', 'OP', 'LP', 'RP', 'START'
    prev = 'START'
    for t in tokens:
        if is_number(t):
            out.append(t)
            prev = 'NUM'
        elif t in '+-*/^':
            # Определяем унарный минус: если '-' стоит на позиции, где ожидался операнд
            if t == '-' and (prev in ('START', 'OP', 'LP')):
                t = 'u-'
            # Выносим из стека все операторы с большими/равными приоритетами
            while stack and stack[-1] != '(' and (
                (precedence(t) < precedence(stack[-1])) or
                (precedence(t) == precedence(stack[-1]) and associativity(t) == 'L')
            ):
                out.append(stack.pop())
            stack.append(t)
            prev = 'OP'
        elif t == '(':
            stack.append(t)
            prev = 'LP'
        elif t == ')':
            # Выталкиваем всё до '('
            while stack and stack[-1] != '(':
                out.append(stack.pop())
            if not stack:
                raise ValueError("Скобки не сбалансированы")
            stack.pop()  # убрать '('
            prev = 'RP'
        else:
            raise ValueError(f"Неизвестный токен: {t}")
    # Очищаем стек
    while stack:
        if stack[-1] in '()':
            raise ValueError("Скобки не сбалансированы")
        out.append(stack.pop())
    return out

def evaluate_rpn(rpn):
    stack = []
    for tok in rpn:
        if is_number(tok):
            stack.append(float(tok))
        elif tok == 'u-':
            if not stack:
                raise ValueError("Недостаточно операндов для унарного минуса")
            a = stack.pop()
            stack.append(-a)
        else:
            if len(stack) < 2:
                raise ValueError("Недостаточно операндов для операции")
            b = stack.pop()
            a = stack.pop()
            if tok == '+':
                stack.append(a + b)
            elif tok == '-':
                stack.append(a - b)
            elif tok == '*':
                stack.append(a * b)
            elif tok == '/':
                stack.append(a / b)
            elif tok == '^':
                stack.append(a ** b)
            else:
                raise ValueError(f"Неизвестная операция: {tok}")
    if len(stack) != 1:
        raise ValueError("Неправильное выражение")
    return stack[0]

def calculate(expr: str) -> float:
    if not expr:
        raise ValueError("Пустое выражение")
    s = preprocess(expr)
    tokens = tokenize(s)
    rpn = to_rpn(tokens)
    result = evaluate_rpn(rpn)
    return result

def main():
    print("Калькулятор для Pydroid3. Введите выражение (пример: 2*(3+4) или -5+2).")
    print("Чтобы выйти, введите exit.")
    while True:
        s = input("Expr> ").strip()
        if s.lower() in ('exit', 'quit', 'q'):
            break
        try:
            res = calculate(s)
            # Округлим для удобства вывода
            print("=", res)
        except Exception as e:
            print("Ошибка:", e)

if __name__ == '__main__':
    main()

Дополнительный вариант: простой графический калькулятор (Tkinter) Если хочешь графический интерфейс (кнопки и дисплей), можно сделать минимальный Tkinter-приложение. Это потребует установленного модуля tkinter в твоем окружении Python. В Pydroid3 он часто доступен. Сообщи, если хочешь такой вариант — дам упрощенный код на Tkinter и объяснение, как его запускать.

Пояснения по базовым концептам (для закрепления)

  • Токены: маленькие части выражения — числа и знаки операций.
  • Постфиксная запись (обратная польская запись): порядок записи, при котором операция идёт после своих операндов, например 3 4 + вместо 3 + 4. Такой подход упрощает вычисления.
  • Унарный минус: минус перед числом без явного числа слева, например −5. В выражении он трактуется как отдельная операция «уар-минус» и вычисляется как отрицательное число.
  • Ассоциативность и приоритеты: какие операции сначала. Возведение в степень выполняется отдельно и справа (правоассоциация), сложение/вычитание — слева направо.

Если хочешь, могу:

  • сделать упрощенную версию без постфикса, но через eval с ограниченным набором разрешённых операций (меньше риска, но менее безопасно без проверок), или
  • адаптировать калькулятор под учебные задачи 4 класса (добавить работу с дробями, проценты и простые примеры).

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