Как добавить корень в калькуляторе на питоне
Перейти к содержимому

Как добавить корень в калькуляторе на питоне

  • автор:

Как извлечь корень в Python

Квадратный корень из числа — это значение, которое при умножении само на себя дает исходное число. Каждое положительное число имеет два квадратных корня (то же значение с положительным и отрицательным знаками). Ниже приводится запись квадратного корня:
√25 = ±5

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

Математическое представление квадрата числа

Все мы в детстве узнали, что, когда число умножается само на себя, мы получаем его квадрат. Также квадрат числа можно представить как многократное умножение этого числа. Попробуем разобраться в этом на примере.

Предположим, мы хотим получить квадрат 5. Если мы умножим число (в данном случае 5) на 5, мы получим квадрат этого числа. Для обозначения квадрата числа используется следующая запись:
5 2 = 25

При программировании на Python довольно часто возникает необходимость использовать функцию извлечения квадратного корня. Есть несколько способов найти квадратный корень числа в Python.

1. Используя оператор возведения в степень

 
num = 25 sqrt = num ** (0.5) print("Квадратный корень из числа "+str(num)+" это "+str(sqrt))
Квадратный корень из числа 25 это 5.0

Объяснение: Мы можем использовать оператор «**» в Python, чтобы получить квадратный корень. Любое число, возведенное в степень 0.5, дает нам квадратный корень из этого числа.

2. Использование math.sqrt()

Квадратный корень из числа можно получить с помощью функции sqrt() из модуля math , как показано ниже. Далее мы увидим три сценария, в которых передадим положительный, нулевой и отрицательный числовые аргументы в sqrt() .

a. Использование положительного числа в качестве аргумента.

 
import math num = 25 sqrt = math.sqrt(num) print("Квадратный корень из числа " + str(num) + " это " + str(sqrt))

Вывод: Квадратный корень из числа 25 это 5.0 .

b. Использование ноля в качестве аргумента.

 
import math num = 0 sqrt = math.sqrt(num) print("Квадратный корень из числа " + str(num) + " это " + str(sqrt))

Вывод: Квадратный корень из числа 0 это 0.0 .

c. Использование отрицательного числа в качестве аргумента.

 
import math num = -25 sqrt = math.sqrt(num) print("Квадратный корень из числа " + str(num) + " это " + str(sqrt))
Traceback (most recent call last): File "C:\wb.py", line 3, in sqrt = math.sqrt(num) ValueError: math domain error

Объяснение: Когда мы передаем отрицательное число в качестве аргумента, мы получаем следующую ошибку «math domain error». Из чего следует, что аргумент должен быть больше 0. Итак, чтобы решить эту проблему, мы должны использовать функцию sqrt() из модуля cmath .

3. Использование cmath.sqrt()

Ниже приведены примеры применения cmath.sqrt() .

а. Использование отрицательного числа в качестве аргумента.

Как правильно написать калькулятор на питоне с помощью eval()

В комментариях к статьям по синтаксическому анализу я иногда вижу такие:

на питоне калькулятор пишется проще простого — print(eval(input()))

Ну, вобщем‑то — да, но если, например, вы прикрутите такой калькулятор к своему сайту, то любой желающий вместо 2+2*2 может написать exec("import os; os.removedirs('/')") , предварительно изучив все ваши секретные файлы подобным же образом. Такая перспектива не может радовать, но и отказываться от eval() тоже не стоит.

— А что делать‑то? — спросите вы. Ответ простой: валидировать входящие данные, как вы это всегда делаете. Только не те, которые передаются функции eval() — для этого вам действительно пришлось бы написать свой синтаксический анализатор, а внутренние данные, которыми оперирует реализация eval() .

— А! Я знаю — скажете вы — используем compile() , валидируем код и тогда уже вызываем eval() . Что-ж, возможно и так. Но я не знаю простого способа валидировать байт‑код. Нет. Нам надо валидировать результат питоновского синтаксического анализатора — абстрактное синтаксическое дерево или AST. Это гораздо проще, хоть и звучит пугающе.

Напишем свой eval() так:

def my_eval(expression): tree = ast.parse(expression, mode='eval') code = compile(tree, filename='', mode='eval') return eval(code)

Нам, естественнно, понадобится модуль ast:

>>> import ast

Проверяем - работает ли?

>>> print(my_eval(input())) 2+2*2 6

Итак, у нас есть tree . Вам, конечно же, любопытно, что там внутри, и действительно, надо же знать, что мы собираемся валидировать. Но просто так посмотреть не получится — это объект, и print() или pprint() выдадут всего лишь Я пользовался такой функцией:

def dump(node): def _format(node, indent): if isinstance(node, ast.AST): print('%sAST %s' % (' ' * indent, node.__class__.__name__)) for a, b in ast.iter_fields(node): print('%s%s' % (' ' * indent, a)) _format(b, indent + 4) elif isinstance(node, list): print('%sLIST %s' % (' ' * indent, node.__class__.__name__)) for x in node: _format(x, indent) else: print('%s%s' % (' ' * indent, repr(node))) _format(node, 0)

Можете вставить dump(tree) в my_eval(), поиграться и посмотреть, какое оно — это дерево. Только не надо копипастить мой пример с removedirs() .

Кому играться лениво — вот пара примеров:

>>> print(my_eval(input())) 2+2*2 AST Expression body AST BinOp left AST Constant value 2 kind None op AST Add right AST BinOp left AST Constant value 2 kind None op AST Mult right AST Constant value 2 kind None 6
>>> print(my_eval(input())) print(globals()) AST Expression body AST Call func AST Name id 'print' ctx AST Load args LIST list AST Call func AST Name id 'globals' ctx AST Load args LIST list keywords LIST list keywords LIST list , '__spec__': None, '__annotations__': <>, '__builtins__': , 'my_eval': , 'ast': , 'dump': > None

Видите, чем отличаются безопасные выражения от небезопасных? Безопасные содержат только Constant и BinOp , а небезопасные — всякие Call и Name . Полный список операций и других узлов дерева можно посмотреть в документации к модулю ast. Это поможет определиться, что запретить, а что разрешить. Для простого калькулятора, я считаю, достаточно разрешить основные операции BinOp и UnaryOp . Плюс Constant .

Пора писать валидатор:

_allowed_nodes = ( # базовые узлы: ast.BinOp, ast.UnaryOp, ast.Constant, # основные BinOps: ast.Add, ast.Sub, ast.Mult, ast.Div, ast.FloorDiv, ast.Mod, ast.Pow, # основные UnaryOps: ast.UAdd, ast.USub ) def validate_ast(tree): # валидируем корень дерева if not isinstance(tree, ast.Expression): raise Exception('Неправильное выражение') # валидируем узлы def validate_children(node): for child in ast.iter_child_nodes(node): if not isinstance(child, _allowed_nodes): raise Exception('Неправильное выражение') validate_children(child) validate_children(tree)

Вот так всё просто. Смело вызывайте эту функцию из my_eval() перед compile() :

def my_eval(expression): tree = ast.parse(expression, mode='eval') validate_ast(tree) code = compile(tree, filename='', mode='eval') return eval(code)

и будет вам счастье. Но, имейте ввиду, документация к функции compile() сообщает:

Warning

It is possible to crash the Python interpreter with a sufficiently large/complex string when compiling to an AST object due to stack depth limitations in Python’s AST compiler.

Так что ограничивайте длину строки, передаваемой my_eval() . И тогда счастье будет настоящим.

— Постойте! — скажете вы — Мне не нужен простой бухгалтерский калькулятор! Где хоть какой-нибудь минимальный набор математических функций? Не отправлять же пользователя в пешее путешествие искать косинус фи?

М-да, пожалуй, соглашусь с вами. Давайте разрешим кое-что из модуля math . Но это будут вызовы функций, а значит — небезопасные области тьмы. Нам придётся добавить ast.Call , ast.Name и ast.Load в _allowed_nodes , и это открывает путь к exec() . Чтобы избежать неприятностей, надо ограничить контекст выполнения, в котором важно наличие пустого __builtins__ :

def my_eval(expression): tree = ast.parse(expression, mode='eval') validate_ast(tree) code = compile(tree, filename='', mode='eval') context = > return eval(code, context)

Плюс, надо добавить поддержку узлов-списков в валидатор:

def validate_ast(tree): # валидируем корень дерева if not isinstance(tree, ast.Expression): raise Exception('Неправильное выражение') # валидируем узлы def validate_children(node): for child in ast.iter_child_nodes(node): if isinstance(child, list): for grandchild in child: validate_children(grandchild) else: if not isinstance(child, _allowed_nodes): raise Exception('Неправильное выражение') validate_children(child) validate_children(tree)

Теперь, если мы введём

NameError: name 'exec' is not defined

Ура! Ничего лучшего я, конечно, придумать не могу, но надеюсь что те, кто умнее меня, напишут в комментариях как это взломать и, соответственно, защититься.

Итак, функции у нас разрешены, надо добавить нужные в контекст выполнения. Я ограничусь синусом и косинусом, остальное вы и сами сможете. По своему вкусу.

import math def my_eval(expression): tree = ast.parse(expression, mode='eval') validate_ast(tree) code = compile(tree, filename='', mode='eval') context = < '__builtins__': <>, 'sin': math.sin, 'cos': math.cos > return eval(code, context)

Может показаться, что достаточно создать контекст всего один раз, вне функции, как мы это сделали с _allowed_nodes в валидаторе, но! — _allowed_nodes у нас всё-таки immutable, а для контекста есть риск модификации, случайной или преднамеренной. Известные аналогичные грабли — использование dict и list в качестве значений по умолчанию для аргументов. Поэтому лучше создавать контекст каждый раз, внутри функции.

Ну, вот собственно, и всё. Пользуйтесь и наслаждайтесь. Для тех, кому лень собирать копипастой всё в кучу, ловите полный исходник:

import ast import math def my_eval(expression): tree = ast.parse(expression, mode='eval') #dump(tree) validate_ast(tree) code = compile(tree, filename='', mode='eval') context = < '__builtins__': <>, 'sin': math.sin, 'cos': math.cos > return eval(code, context) _allowed_nodes = ( # базовые узлы: ast.BinOp, ast.UnaryOp, ast.Constant, ast.Call, ast.Name, ast.Load, # основные BinOps: ast.Add, ast.Sub, ast.Mult, ast.Div, ast.FloorDiv, ast.Mod, ast.Pow, # основные UnaryOps: ast.UAdd, ast.USub ) def validate_ast(tree): # валидируем корень дерева if not isinstance(tree, ast.Expression): raise Exception('Неправильное выражение') # валидируем узлы def validate_children(node): for child in ast.iter_child_nodes(node): if isinstance(child, list): for grandchild in child: validate_children(grandchild) else: if not isinstance(child, _allowed_nodes): raise Exception('Неправильное выражение') validate_children(child) validate_children(tree) def dump(node): def _format(node, indent): if isinstance(node, ast.AST): print('%sAST %s' % (' ' * indent, node.__class__.__name__)) for a, b in ast.iter_fields(node): print('%s%s' % (' ' * indent, a)) _format(b, indent + 4) elif isinstance(node, list): print('%sLIST %s' % (' ' * indent, node.__class__.__name__)) for x in node: _format(x, indent) else: print('%s%s' % (' ' * indent, repr(node))) _format(node, 0) print(my_eval(input()))
  • Python
  • Программирование

Программа "Простейший калькулятор"

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

Решение задачи на языке программирования Python

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

Если пользователь ввел знак, который не является ни знаком арифметической операции, ни символом-"прерывателем" работы программы, то вывести сообщение о некорректном вводе.

Если был введен один из четырех знаков операции, запросить ввод двух чисел.

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

Если было выбрано деление, необходимо проверить не является ли нулем второе число. Если это так, то сообщить о невозможности деления.

print("0 в качестве знака операции" "\nзавершит работу программы\n") while True: s = input("Знак (+, -, *, /): ") if s == '0': break if s in ('+', '-', '*', '/'): a = float(input("a = ")) b = float(input("b = ")) if s == '+': print("%.2f" % (a + b)) elif s == '-': print("%.2f" % (a - b)) elif s == '*': print("%.2f" % (a * b)) elif s == '/': if b != 0: print("%.2f" % (a / b)) else: print("Деление на ноль!") else: print("Неверный знак операции!")

Пример выполнения программы:

0 в качестве знака операции завершит работу программы Знак (+, -, *, /): / a = -9.34 b = 3.215 -2.91 Знак (+, -, *, /): & Неверный знак операции! Знак (+, -, *, /): - a = 4005 b = 1358 2647.00 Знак (+, -, *, /): 0

Вариант решение задачи с помощью оператора match (появился в Python 3.10):

print("0 в качестве знака - выход из программы\n") while True: s = input("Знак (+, -, *, /): ") if s in ('+', '-', '*', '/'): a = float(input("a = ")) b = float(input("b = ")) match s: case '+': print("%.2f" % (a + b)) case '-': print("%.2f" % (a - b)) case '*': print("%.2f" % (a * b)) case '/': if b != 0: print("%.2f" % (a / b)) else: print("Деление на ноль!") case '0': break case _: print("Неверный знак операции!")

X Скрыть Наверх

Решение задач на Python

Кнопка возведения в корень в калькуляторе

Есть программа, это калькулятор. Задача добавить кнопку которая будет извлекать корень из введеного. Кнопку я добавил, но как извлечь корень - не могу понять, пробую при помощи функцию math и math.sqrt() но не выходит, пробовал просто оператор извлечения ** - тоже не хочет. Кнопка 17. Подскажите как сделать. UPD: пытаюсь функцией сделать которая по кнопке вызывается, тоже не хочет, Вот код калькулятора:

from tkinter import * import math #from tkinter.ttk import Radiobutton window = Tk() oper=["+","-","*","/"] number = IntVar() window.geometry('200x250') global operand1, lastop, lastres lastop=0 operand1=0 lastres=0 def add(): label1["text"] = label1["text"] + str(number.get()) label2["text"] = label2["text"] + str(number.get()) def op(): global operand1 global lastop operand1=int(label1["text"]) label1["text"] = "" lastres=operand1 lastop=number.get() label2["text"] = label2["text"] + label1["text"] label2["text"] = label2["text"] + oper[lastop-11] #if lastres!=0: #operand1+=lastres #print("Увеличили операнд1", operand1) #lastres=0 if lastop==11: print("lastres= ",lastres,"operand1= ",operand1) lastres+=operand1 operand1+=int(label1["text"]) print("lastres= ",lastres,"operand1= ",operand1) def vyvod(): global operand1 global lastop global lastres if lastop==11: operand1+=int(label1["text"]) label1["text"] = str(operand1) label2["text"] = label2["text"] + " = " + label1["text"] if lastop==12: operand1-=int(label1["text"]) label1["text"] = str(operand1) label2["text"] = label2["text"] + " = " + label1["text"] elif lastop==13: operand1*=int(label1["text"]) label1["text"] = str(operand1) label2["text"] = label2["text"] + " = " + label1["text"] elif lastop==14: operand1/=int(label1["text"]) label1["text"] = str(operand1) label2["text"] = label2["text"] + " = " + label1["text"] elif lastop==17: operand1**=int(label1["text"]) label1["text"] = str(operand1) label2["text"] = label2["text"] + " = " + label1["text"] else: print("Ошибка в операции") def koren(): operand1=int(label1(math.sqrt(["text"]))) label1["text"] = str(operand1) label2["text"] = label2["text"] + " = " + label1["text"] def clean(): global operand1 global lastop global lastres operand1=0 lastop=0 lastres=0 label1["text"] = "" label2["text"] = "" btn1=Radiobutton(window,indicatoron=0,text="1",width=2,variable=number,value=1,command=add,bg="lightgreen") btn2=Radiobutton(window,indicatoron=0,text="2",width=2,variable=number,value=2,command=add,bg="lightgreen") btn3=Radiobutton(window,indicatoron=0,text="3",width=2,variable=number,value=3,command=add,bg="lightgreen") btn4=Radiobutton(window,indicatoron=0,text="4",width=2,variable=number,value=4,command=add,bg="lightgreen") btn5=Radiobutton(window,indicatoron=0,text="5",width=2,variable=number,value=5,command=add,bg="lightgreen") btn6=Radiobutton(window,indicatoron=0,text="6",width=2,variable=number,value=6,command=add,bg="lightgreen") btn7=Radiobutton(window,indicatoron=0,text="7",width=2,variable=number,value=7,command=add,bg="lightgreen") btn8=Radiobutton(window,indicatoron=0,text="8",width=2,variable=number,value=8,command=add,bg="lightgreen") btn9=Radiobutton(window,indicatoron=0,text="9",width=2,variable=number,value=9,command=add,bg="lightgreen") btn0=Radiobutton(window,indicatoron=0,text="0",width=2,variable=number,value=0,command=add,bg="lightgreen") btn11=Radiobutton(window,indicatoron=0,width=2,text="+",variable=number,value=11,command=op,bg="lightblue") btn12=Radiobutton(window,indicatoron=0,width=2,text="-",variable=number,value=12,command=op,bg="lightblue") btn13=Radiobutton(window,indicatoron=0,width=2,text="*",variable=number,value=13,command=op,bg="lightblue") btn14=Radiobutton(window,indicatoron=0,width=2,text="/",variable=number,value=14,command=op,bg="lightblue") btn15=Radiobutton(window,indicatoron=0,width=2,text="=",variable=number,value=15,command=vyvod) btn16=Radiobutton(window,indicatoron=0,width=2,text="C",variable=number,value=16,command=clean,bg="red") btn17=Radiobutton(window,indicatoron=0,width=2,text="√",variable=number,value=17,command=koren,bg="lightblue") btn18=Radiobutton(window,indicatoron=0,width=2,text="DL",variable=number,value=18,command=clean,bg="red") btn1.grid(row=0, column=0) btn2.grid(row=0, column=1) btn3.grid(row=0, column=2) btn4.grid(row=1, column=0) btn5.grid(row=1, column=1) btn6.grid(row=1, column=2) btn7.grid(row=2, column=0) btn8.grid(row=2, column=1) btn9.grid(row=2, column=2) btn0.grid(row=3, column=1) btn11.grid(row=0, column=3) btn12.grid(row=1, column=3) btn13.grid(row=2, column=3) btn14.grid(row=3, column=3) btn15.grid(row=3, column=4) btn16.grid(row=3, column=0) btn17.grid(row=3, column=4) btn18.grid(row=3, column=2) frame = Frame(master=window, height=1, borderwidth=5,bg="red") frame.grid(row=4, column=0,columnspan=3) label1 = Label(master=window, width=15, height=1,text="", bg="yellow") label1.grid(row=4, column=0,columnspan=3,pady=10) label2 = Label(master=window, width=30, height=1,text="", bg="yellow") label2.grid(row=5, column=0,columnspan=6,sticky = W) window.mainloop() 

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *