Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Trigonometry in python calculator

I’m writing a scientific calculator as part of a project, but when I click the "=" sign, 6 functions (coth, acot, sec, sech, asec and acsc) display an error message in the calculation field instead of the result. The rest displays the correct result in radians. I can only use the math module, so I tried to create equivalents of the given functions using inversions of other running ones. Unfortunately, this solution only worked in my case 1/3 of the time. I am attaching a code snippet containing trigonometry, numbers and basic mathematical operations.

import tkinter as tk
import math

class ScientificCalculator:
    def __init__(self, root):
        self.root = root
        root.title("Kalkulator Naukowy")
        self.expression = ""
        self.max_history_lines = 10
        self.memory = 0

        self.display = tk.Entry(root, width=40, font=('Arial', 20), borderwidth=5)
        self.display.grid(row=0, column=0, columnspan=7, pady=(20, 10))

        buttons = [
            "7", "8", "9", "+", "sin(", "sinh(", "asin(",
            "4", "5", "6", "-", "cos(", "cosh(", "acos(",
            "1", "2", "3", "*", "tan(", "tanh(", "atan(",
            "0", ".", "(", ")", "=", "AC", "C", "cot(", 
            "coth(", "acot(", "sec(", "sech(", "asec(", "csc(", "csch(",
            "acsc("
        ]

        row_val = 1
        col_val = 0

        for button in buttons:
            if button == "=":
                tk.Button(root, text=button, padx=30, pady=20, command=lambda b=button: self.button_click(b), font=('Arial', 14, 'bold'), bg='#082e79', fg='white').grid(row=row_val, column=col_val, columnspan=2, sticky='nsew')
                col_val += 2
            elif button in ["C", "AC"]:
                tk.Button(root, text=button, padx=30, pady=20, command=lambda b=button: self.button_click(b), font=('Arial', 14, 'bold'), bg='#082e79', fg='white').grid(row=row_val, column=col_val, columnspan=2, sticky='nsew')
                col_val += 2
            else:
                tk.Button(root, text=button, padx=20, pady=20, command=lambda b=button: self.button_click(b), font=('Arial', 14, 'bold'), bg='#666666', fg='white').grid(row=row_val, column=col_val, padx=1, pady=1, sticky='nsew')
                col_val += 1

            if col_val > 6:
                col_val = 0
                row_val += 1

        self.history_text = tk.Text(root, height=10, width=40)
        self.history_text.grid(row=10, column=0, columnspan=7, padx=2, pady=2, sticky='nsew')

        self.history = []

    def button_click(self, button):
        if button == "=":
            try:
                self.expression = self.expression.replace("cot(", "1/math.tan(")  
                self.expression = self.expression.replace("coth(", "1/math.tanh(")  
                self.expression = self.expression.replace("acot(", "1/math.atan(")  
                self.expression = self.expression.replace("sec(", "1/math.cos(")
                self.expression = self.expression.replace("sech(", "1/math.cosh(")
                self.expression = self.expression.replace("asec(", "1/math.acos(")
                self.expression = self.expression.replace("csc(", "1/math.sin(")
                self.expression = self.expression.replace("csch(", "1/math.sinh(")
                self.expression = self.expression.replace("acsc(", "1/math.asin(")
                result = str(eval(self.expression))
                history_expression = self.expression
                self.history.insert(0, history_expression + " = " + result)
                self.display.delete(0, tk.END)
                self.display.insert(0, result)
                self.update_history()
                self.expression = result
            except Exception:
                self.display.delete(0, tk.END)
                self.display.insert(0, "Błąd")
        elif button == "C":
            self.expression = ""
            self.display.delete(0, tk.END)
        elif button == "AC":
            self.memory = 0
            self.expression = ""
            self.display.delete(0, tk.END)
            self.history = [] 
            self.update_history()
        else:
            if button in ["sin(", "cos(", "tan(", "sinh(", "cosh(", "tanh(", "asin(", "acos(", "atan("]:
                self.expression += "math." + button
            else:
                self.expression += button
            self.display.insert(tk.END, button)

    def update_history(self):
        if len(self.history) > self.max_history_lines:
            self.history = self.history[:self.max_history_lines]
        self.history_text.delete(1.0, tk.END)
        for item in self.history:
            self.history_text.insert(tk.END, item + "\n")

if __name__ == "__main__":
    root = tk.Tk()
    calc = ScientificCalculator(root)
    root.geometry("750x730")
    root.configure(bg="#bfbfbf")
    root.mainloop()

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Thanks for the question, and welcome to SO.

The first steps to solving this issue are printing a more detailed error message.
Catching the Exception tells us there is a problem, not what problem is happening.

We can know that exactly by making a modification like so:

        # ...
        self.expression = result
    except Exception as e:
        self.display.delete(0, tk.END)
        self.display.insert(0, "Błąd")
        print("Exception:", e)
        # ...

Adding this, and trying to evaluate acsc(-0.5), I get an error message:

Exception: name 'a1' is not defined

That name, a1 is not present anywhere in the given snippet, so let’s dig deeper:

I add a line inside button_click that prints the exact expression that’s being evaluated:

    # ...
    self.expression = self.expression.replace("acsc(", "1/math.asin(")
    print("Expression before eval:",self.expression)
    result = str(eval(self.expression))
    # ...

Running the code again with the same input, the problem becomes clear immediately:

Expression before eval: a1/math.sin(-0.5)
Exception: name 'a1' is not defined

acsc(-0.5) should have become 1/math.asin(-0.5). Instead, it became a1/math.sin(-0.5). This is the hint we need to finally solve the problem. Let’s look at the part of the code that is supposed to do the replacement:

    # ...
    self.expression = self.expression.replace("csc(", "1/math.sin(")
    self.expression = self.expression.replace("csch(", "1/math.sinh(")
    self.expression = self.expression.replace("acsc(", "1/math.asin(")

Python executes things from top to bottom. The first replacement happens before the last one.

Thus, the csc(-0.5) part from acsc(-0.5) gets substituted, and the rest of the replacements don’t do anything.

We can finally solve the problem by changing the order.

    self.expression = self.expression.replace("acot(", "1/math.atan(")  
    self.expression = self.expression.replace("cot(", "1/math.tan(")  
    self.expression = self.expression.replace("coth(", "1/math.tanh(")  
    self.expression = self.expression.replace("asec(", "1/math.acos(")
    self.expression = self.expression.replace("sec(", "1/math.cos(")
    self.expression = self.expression.replace("sech(", "1/math.cosh(")
    self.expression = self.expression.replace("acsc(", "1/math.asin(")
    self.expression = self.expression.replace("csc(", "1/math.sin(")
    self.expression = self.expression.replace("csch(", "1/math.sinh(")

Making this change, when I enter acsc(-0.5), into the new program, I get the value as -1.9098593171027438 which is the correct and expected output.

I hope this was helpful for you to understand about the issue you faced, and how you can approach issues in the future.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading