Friday, April 25, 2025

Calculator

Now for something completely different.

Imagine, you have an embedded system that does not support high level floating point operations such as sqrt(), sin(), ….. It only implements arithmetic operations such as +, -, *, /.

In this case, you‘ll need to implement those higher level functions yourself. I wrote a small calculator that implements high level functions based on arithmetic operations by using algorithms such as the Taylor series and the Newton-Ralphson method. 

I also created the program, because I was interested in how calculators may implement these functions. 


#Calculator


import math


class ScientificCalculator:

    def __init__(self):

        pass


    def factorial(self, n):

        if n == 0 or n == 1:

            return 1

        result = 1

        for i in range(2, n + 1):

            result *= i

        return result


    def power(self, base, exp):

        # Handle fractional exponents

        if exp < 0:

            return 1 / self.power(base, -exp)

        if isinstance(exp, float) and exp != int(exp):

            numerator, denominator = self._fractional_parts(exp)

            root = self.nth_root(base, denominator)

            return self.power(root, numerator)

        result = 1

        for _ in range(abs(int(exp))):

            result *= base

        return result if exp >= 0 else 1 / result


    def nth_root(self, x, n, iterations=10):

        """Calculate the nth root of x using Newton's method."""

        if x < 0 and n % 2 == 0:

            raise ValueError("Even roots of negative numbers are undefined.")

        guess = x / n

        for _ in range(iterations):

            guess = ((n - 1) * guess + x / (guess ** (n - 1))) / n

        return guess


    def _fractional_parts(self, exp):

        """Split a fractional exponent into numerator and denominator."""

        denominator = 10 ** len(str(exp).split(".")[1])

        numerator = int(exp * denominator)

        gcd = math.gcd(numerator, denominator)

        return numerator // gcd, denominator // gcd


    def taylor_sin(self, x, terms=10):

        x = x % (2 * math.pi)  # Normalize to [0, 2π]

        result = 0

        for n in range(terms):

            term = self.power(-1, n) * self.power(x, 2 * n + 1) / self.factorial(2 * n + 1)

            result += term

        return result


    def taylor_cos(self, x, terms=10):

        x = x % (2 * math.pi)  # Normalize to [0, 2π]

        result = 0

        for n in range(terms):

            term = self.power(-1, n) * self.power(x, 2 * n) / self.factorial(2 * n)

            result += term

        return result


    def taylor_exp(self, x, terms=10):

        result = 0

        for n in range(terms):

            term = self.power(x, n) / self.factorial(n)

            result += term

        return result


    def natural_log(self, x, terms=10):

        if x <= 0:

            raise ValueError("Logarithm undefined for non-positive values.")

        if x == 1:

            return 0

        if x < 1:

            x = 1 / x

            invert = True

        else:

            invert = False

        x -= 1

        result = 0

        for n in range(1, terms + 1):

            term = self.power(-1, n + 1) * self.power(x, n) / n

            result += term

        return -result if invert else result


    def square_root(self, x, iterations=10):

        if x < 0:

            raise ValueError("Square root undefined for negative values.")

        guess = x / 2

        for _ in range(iterations):

            guess = (guess + x / guess) / 2

        return guess


    def calculate(self, operation, *args):

        if operation == "sin":

            return self.taylor_sin(args[0])

        elif operation == "cos":

            return self.taylor_cos(args[0])

        elif operation == "exp":

            return self.taylor_exp(args[0])

        elif operation == "ln":

            return self.natural_log(args[0])

        elif operation == "sqrt":

            return self.square_root(args[0])

        elif operation == "power":

            return self.power(args[0], args[1])

        else:

            raise ValueError("Unsupported operation.")


# Example usage

calc = ScientificCalculator()

print("0.5^1.5:", calc.calculate("power", 0.5, 1.5))

print("sin(π/2):", calc.calculate("sin", math.pi / 2))

print("cos(π):", calc.calculate("cos", math.pi))

print("exp(1):", calc.calculate("exp", 1))

print("ln(2):", calc.calculate("ln", 2))

print("sqrt(16):", calc.calculate("sqrt", 16))

print("2^3:", calc.calculate("power", 2, 3))







No comments: