SoFunction
Updated on 2024-11-15

Scientific Calculator in Python

In this article, we share the example of Python language to achieve the specific code of the scientific calculator for your reference, the details are as follows

Self-study Python language for a month, or white, send a scientific calculator code, I hope you criticize and correct, encouragement.

from tkinter import *
from functools import partial
from calculate import *


# Generate the main calculator screen
def buju(root):
    menu = Menu(root)  # Menu
    submenu1 = Menu(menu, tearoff=0)  # Split window, 0 is in the original window, 1 is clicked to split into two windows
    menu.add_cascade(label='Edit', menu=submenu1)  # Add sub-option (label parameter is what to display)
    submenu1.add_command(label='Copy', command=lambda: bianji(entry, 'copy'))  # Add command
    submenu1.add_command(label='Cut', command=lambda: bianji(entry, 'cut'))
    submenu1.add_command(label='Paste', command=lambda: bianji(entry, 'paste'))
    submenu2 = Menu(menu, tearoff=0)
    menu.add_cascade(label='View', menu=submenu2)
    submenu2.add_command(label='Help', command=lambda: chakan(entry, 'help'))
    submenu2.add_command(label='The Author', command=lambda: chakan(entry, 'author'))
    (menu=menu)  # Reconfigure, add menu

    label = Label(root, width=29, height=1, bd=5, bg='#FFFACD', anchor='se',
                  textvariable=label_text)  # tags, which can display text or images
    (row=0, columnspan=5)  # layouts, registers and displays controls to the window; rowspan: sets the number of columns the cell spans vertically

    entry = Entry(root, width=23, bd=5, bg='#FFFACD', justify="right", font=('Microsoft Black', 12)) # Text box (single line)
    (row=1, column=0, columnspan=5, sticky=N + W + S + E, padx=5, pady=5)  # Set the size of the blank area around the control to be preserved in the x and y directions

    myButton = partial(Button, root, width=5, cursor='hand2', activebackground='#90EE90') # biased functions: functions with fixed arguments
    button_sin = myButton(text='sin', command=lambda: get_input(entry, 'sin('))  # Buttons
    button_arcsin = myButton(text='arcsin', command=lambda: get_input(entry, 'arcsin('))
    button_exp = myButton(text='e', command=lambda: get_input(entry, 'e'))
    button_ln = myButton(text='ln', command=lambda: get_input(entry, 'ln('))
    button_xy = myButton(text='x^y', command=lambda: get_input(entry, '^'))
    button_sin.grid(row=2, column=0)
    button_arcsin.grid(row=2, column=1)
    button_exp.grid(row=2, column=2)
    button_ln.grid(row=2, column=3)
    button_xy.grid(row=2, column=4)

    button_shanyige = myButton(text='←', command=lambda: backspace(entry))  # command specifies the callback function for button messages
    button_shanquanbu = myButton(text=' C ', command=lambda: clear(entry))
    button_zuokuohao = myButton(text='(', command=lambda: get_input(entry, '('))
    button_youkuohao = myButton(text=')', command=lambda: get_input(entry, ')'))
    button_genhao = myButton(text='√x', command=lambda: get_input(entry, '√('))
    button_shanyige.grid(row=3, column=0)
    button_shanquanbu.grid(row=3, column=1)
    button_zuokuohao.grid(row=3, column=2)
    button_youkuohao.grid(row=3, column=3)
    button_genhao.grid(row=3, column=4)

    button_7 = myButton(text=' 7 ', command=lambda: get_input(entry, '7'))
    button_8 = myButton(text=' 8 ', command=lambda: get_input(entry, '8'))
    button_9 = myButton(text=' 9 ', command=lambda: get_input(entry, '9'))
    button_chu = myButton(text=' / ', command=lambda: get_input(entry, '/'))
    button_yu = myButton(text='%', command=lambda: get_input(entry, '%'))
    button_7.grid(row=4, column=0)
    button_8.grid(row=4, column=1)
    button_9.grid(row=4, column=2)
    button_chu.grid(row=4, column=3)
    button_yu.grid(row=4, column=4)

    button_4 = myButton(text=' 4 ', command=lambda: get_input(entry, '4'))
    button_5 = myButton(text=' 5 ', command=lambda: get_input(entry, '5'))
    button_6 = myButton(text=' 6 ', command=lambda: get_input(entry, '6'))
    button_cheng = myButton(text=' * ', command=lambda: get_input(entry, '*'))
    button_jiecheng = myButton(text='Binary', command=lambda: jinzhi(entry))
    button_4.grid(row=5, column=0)
    button_5.grid(row=5, column=1)
    button_6.grid(row=5, column=2)
    button_cheng.grid(row=5, column=3)
    button_jiecheng.grid(row=5, column=4)

    button_1 = myButton(text=' 1 ', command=lambda: get_input(entry, '1'))
    button_2 = myButton(text=' 2 ', command=lambda: get_input(entry, '2'))
    button_3 = myButton(text=' 3 ', command=lambda: get_input(entry, '3'))
    button_jian = myButton(text=' - ', command=lambda: get_input(entry, '-'))
    button_dengyu = myButton(text=' \n = \n ', command=lambda: calculator(entry))
    button_1.grid(row=6, column=0)
    button_2.grid(row=6, column=1)
    button_3.grid(row=6, column=2)
    button_jian.grid(row=6, column=3)
    button_dengyu.grid(row=6, column=4, rowspan=2)  # rowspan: set the number of rows a cell spans horizontally

    button_pai = myButton(text=' π ', command=lambda: get_input(entry, 'π'))
    button_0 = myButton(text=' 0 ', command=lambda: get_input(entry, '0'))
    button_xiaoshudian = myButton(text=' . ', command=lambda: get_input(entry, '.'))
    button_jia = myButton(text=' + ', command=lambda: get_input(entry, '+'))
    button_pai.grid(row=7, column=0)
    button_0.grid(row=7, column=1)
    button_xiaoshudian.grid(row=7, column=2)
    button_jia.grid(row=7, column=3)


# Copy, cut or paste the equation or answer in the text box
def bianji(entry, argu):
    """
    :param entry: text box
    :param argu: the value of the button
    """
    if argu == 'copy':
        entry.event_generate("<<Copy>>")
    elif argu == 'cut':
        entry.event_generate("<<Cut>>")
        clear(entry)
    elif argu == 'paste':
        entry.event_generate("<<Paste>>")


# View usage help and author information
def chakan(entry, argu):
    root = Tk()
    (0, 0)
    text = Text(root, width=20, height=2, bd=5, bg='#FFFACD', font=('Microsoft Black', 12))
    (padx=5, pady=5)
    if argu == 'help':
        ('Help')
        (INSERT, 'How simple this calculator is! \n')
        (INSERT, 'Just don't ask me for help!')
    elif argu == 'author':
        ('The Author')
        (INSERT, 'Author: Ji Liangdong\n')
        (INSERT, 'Time:2019-07-08')


# Delete last entry
def backspace(entry):
    (len(()) - 1)  # Delete the last input value of the text box


# Delete all inputs and displays
def clear(entry):
    (0, END)  # Delete all contents of the text box
    label_text.set('')


# Add content to the text box after clicking the calculator input button
def get_input(entry, argu):
    formula = ()
    for char in formula:
        if '\u4e00' <= char <= '\u9fa5':
            clear(entry)  # Delete the display of Chinese characters in the text box to reduce manual deletion operations
    (INSERT, argu)  # When using END, the combination of keystrokes and keystrokes will result in an error.


# Convert decimal integers to binary integers
def jinzhi(entry):
    try:
        formula = ()
        if ('\d+$', formula):
            number = int(formula)
            cunchu = []  # Place the remainder of each division by 2
            result = ''
            while number:
                (number % 2)
                number //= 2  # Integer division, return quotient
            while cunchu:
                result += str(())  # Invert all the remainders to get the result
            clear(entry)
            (END, result)
            label_text.set(''.join(formula + '='))
        else:
            clear(entry)
            (END, 'Please enter a decimal integer')
    except:
        clear(entry)
        (END, 'Error')


# Calculate by clicking on "="
def calculator(entry):
    try:
        formula = ()
        # When the input is only a number or π or e, it is still displayed.
        if ('-?[\d+,π,e]\.?\d*$', formula):
            label_text.set(''.join(formula + '='))
            return
        # When the input is an equation, the result is displayed.
        result = final_calc(formula_format(formula))
        clear(entry)
        (END, result)  # Output the results into a text box
        label_text.set(''.join(formula + '='))
    except:
        clear(entry)
        (END, 'Error')


if __name__ == '__main__':
    root = Tk()  # Generate windows
    ('Rijo Calculator')  # Name of the window
    (0, 0)  # Window size adjustability, denoting variability in x, y directions, respectively
    global label_text  # Define global variables
    label_text = StringVar()
    buju(root)
    ()  # Entering the message loop(required component),Otherwise the generated window flickers

import re
from math import *


# Handle arithmetic from strings to lists, solving the problem of whether the crossbar is a minus or minus sign
def formula_format(formula):
    """
    :param formula: str
    """
    formula = (' ', '', formula)  # Remove all spaces in the equation s
    # Split by 'horizontal bar number', where regular expression: (\-\d+\...????) \d*) in parentheses:
    # \- means match the beginning of the bar; \d+ means match the number one or more times; \...? means match the decimal point 0 or 1 time; \d* means match the number 0 or more times.
    formula_list = [i for i in ('(-[\d+,π,e]\.?\d*)', formula) if i]
    final_formula = []  # Final list of equations
    for item in formula_list:
        # If the equation starts with a bar, the first number is negative and the bar is a negative sign
        if len(final_formula) == 0 and ('-[\d+,π,e]\.?\d*$', item):
            final_formula.append(item)
            continue
        # If the last element of the current list of equations is the operator ['+', '-', '*', '/', '(', '%', '^'], the bar is a minus sign.
        if len(final_formula) > 0:
            if ('[\+\-\*\/\(\%\^]$', final_formula[-1]):
                final_formula.append(item)
                continue
        # Split by operator
        item_split = [i for i in ('([\+\-\*\/\(\)\%\^\√])', item) if i]
        final_formula += item_split
    return final_formula


# Determine whether it is an operator, if so return True
def is_operator(e):
    """
    :param e: str
    :return: bool
    """
    opers = ['+', '-', '*', '/', '(', ')', '%', '^', '√', 'sin', 'arcsin', 'ln']
    return True if e in opers else False  # Nesting if and else statements in for loops


# Compare two consecutive operators to determine whether to press or pop a stack
def decision(tail_op, now_op):
    """
    :param tail_op: The last operator in the operator stack
    :param now_op: The current operator from the arithmetic list.
    :return: 1represent a pop-up operation (computing),0stands for popping the last element of the operator stack'(',-1push on a stack
    """
    # Define 4 operator levels
    rate1 = ['+', '-']
    rate2 = ['*', '/', '%']
    rate3 = ['^', '√', 'sin', 'arcsin', 'ln']
    rate4 = ['(']
    rate5 = [')']

    if tail_op in rate1:
        if now_op in rate2 or now_op in rate3 or now_op in rate4:
            return -1  # Indicates that the current operator has a higher priority than the last operator on the operator stack and needs to be stacked.
        else:
            return 1  # Indicates that the current operator priority is equal to the last operator on the operator stack and needs to be bounced

    elif tail_op in rate2:
        if now_op in rate3 or now_op in rate4:
            return -1
        else:
            return 1

    elif tail_op in rate3:
        if now_op in rate4:
            return -1
        else:
            return 1

    elif tail_op in rate4:
        if now_op in rate5:
            return 0  # '('meets')', need to pop up '('and drops')' to indicate that the equation in the parentheses has been computed and the result pressed into the number stack
        else:
            return -1  # Press into the stack whenever the top element of the stack is '(' and the current element is not ')'


# Pass in two numbers, one operator, and return the corresponding result depending on the operator.
def calculate(n1, n2, operator):
    """
    :param n1: float
    :param n2: float
    :param operator: + - * / % ^
    :return: float
    """
    result = 0
    if operator == '+':
        result = n1 + n2
    if operator == '-':
        result = n1 - n2
    if operator == '*':
        result = n1 * n2
    if operator == '/':
        result = n1 / n2
    if operator == '%':
        result = n1 % n2
    if operator == '^':
        result = n1 ** n2
    return result


# Calculate √(), sin(), or arcsin() after finding the result of the equation in parentheses.
def gaojie(op_stack, num_stack):
    if op_stack[-1] == '√':
        op = op_stack.pop()
        num2 = num_stack.pop()
        num_stack.append(sqrt(num2))
    elif op_stack[-1] == 'sin':
        op = op_stack.pop()
        num2 = num_stack.pop()
        num_stack.append(sin(num2))
    elif op_stack[-1] == 'arcsin':
        op = op_stack.pop()
        num2 = num_stack.pop()
        num_stack.append(asin(num2))
    elif op_stack[-1] == 'ln':
        op = op_stack.pop()
        num2 = num_stack.pop()
        num_stack.append(log(num2))


# Responsible for iterating through the list of characters in the equation and deciding whether to press them into the number stack or into the operator stack or pop the stack
def final_calc(formula_list):
    """
    :param formula_list: list of formulas
    :return: Calculation result
    """
    num_stack = []  # Digital stacks
    op_stack = []  # Operator stack
    for item in formula_list:
        operator = is_operator(item)
        # Press into the digital stack
        if not operator:
            # π and e converted to values that can be used in calculations
            if item == 'π':
                num_stack.append(pi)
            elif item == '-π':
                num_stack.append(-pi)
            elif item == 'e':
                num_stack.append(e)
            elif item == '-e':
                num_stack.append(-e)
            else:
                num_stack.append(float(item))  # String to float conversion
        # If it's an operator
        else:
            while True:
                # Unconditional stack entry if operator stack is empty
                if len(op_stack) == 0:
                    op_stack.append(item)
                    break
                # Decide to press or pop the stack
                tag = decision(op_stack[-1], item)
                # If -1, press into operator stack and go to next loop
                if tag == -1:
                    op_stack.append(item)
                    break
                # If 0, pop the last '(' in the operator stack and drop the current ')', go to the next loop
                elif tag == 0:
                    op_stack.pop()
                    gaojie(op_stack, num_stack)  # When '(' is preceded by '√', 'sin' or 'arcsin', perform the corresponding operation on the result of the equation in parentheses
                    break
                # If 1, pop the last element in the operator stack and the last two elements in the number stack
                elif tag == 1:
                    if item in ['√', 'sin', 'arcsin']:
                        op_stack.append(item)
                        break
                    op = op_stack.pop()
                    num2 = num_stack.pop()
                    num1 = num_stack.pop()
                    # Presses the result of the calculation onto the number stack and continues the loop until it encounters a break.
                    num_stack.append(calculate(num1, num2, op))
    # Situations where there may still be elements in the number and operator stacks at the end of the big loop
    while len(op_stack) != 0:
        op = op_stack.pop()
        num2 = num_stack.pop()
        num1 = num_stack.pop()
        num_stack.append(calculate(num1, num2, op))
    result = str(num_stack[0])
    # Remove invalid zeros and decimal points, example: 1.0 converted to 1
    if result[len(result) - 1] == '0' and result[len(result) - 2] == '.':
        result = result[0:-2]
    return result


if __name__ == '__main__':
    # formula = "2 * ( 3 - 5 * ( - 6 + 3 * 2 / 2 ) )"
    formula = "arcsin ( 0 )"
    formula_list = formula_format(formula)
    result = final_calc(formula_list)
    print("Arithmetic:", formula)
    print("Calculations:", result)

This is the whole content of this article.