rust
====

Here you will see the Full Rust implementation

.. code-block:: rust

    use pyo3::prelude::*;
    use pyo3::exceptions::PyException;
    use pyo3::create_exception;

    create_exception!(highpymath, MathTypeError, PyException);
    create_exception!(highpymath, MathValueError, PyException);
    create_exception!(highpymath, GeometryError, MathValueError);

    #[cfg(target_pointer_width = "32")]
    type PyFloat = f32;
    #[cfg(target_pointer_width = "64")]
    type PyFloat = f64;

    #[cfg(target_pointer_width = "32")]
    type PyInt = i32;
    #[cfg(target_pointer_width = "64")]
    type PyInt = i64;

    #[cfg(target_pointer_width = "32")]
    type PyIntLong = i64;
    #[cfg(target_pointer_width = "64")]
    type PyIntLong = i128;

    #[cfg(target_pointer_width = "32")]
    type PyUInt = u32;
    #[cfg(target_pointer_width = "64")]
    type PyUInt = u64;

    #[pyfunction]
    fn sum(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(a + b)
    }

    #[pyfunction]
    fn sub(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(a - b)
    }

    #[pyfunction]
    fn mul(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(a * b)
    }

    #[pyfunction]
    fn div(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        if b == 0.0 {
            Err(MathValueError::new_err("Division by Zero"))
        } else {
            Ok(a / b)
        }
    }

    #[pyfunction]
    fn exp(base: PyFloat, power: PyFloat) -> PyResult<PyFloat> {
        Ok(base.powf(power))
    }

    #[pyfunction]
    fn exp2(base: PyFloat) -> PyResult<PyFloat> {
        let _result = base.powf(2.0);
        Ok(_result)
    }

    #[pyfunction]
    fn sqrt(base: PyFloat, power: PyFloat) -> PyResult<PyFloat> {
        if base < 0.0 && power % 2.0 == 0.0 {
            Err(MathValueError::new_err("Negative Base for even Power"))
        } else {
            Ok(base.powf(1.0 / power))
        }
    }

    #[pyfunction]
    fn sqrt2(base: PyFloat) -> PyResult<PyFloat> {
        Ok(base.sqrt())
    }

    #[pyfunction]
    fn log(base: PyFloat, power: PyFloat) -> PyResult<PyFloat> {
        if base <= 0.0 || base == 1.0 {
            Err(MathValueError::new_err("Base must be greater than 0 and not equal to 1"))
        } else if power <= 0.0 {
            Err(MathValueError::new_err("Power must be greater than 0"))
        } else {
            Ok(base.log(power))
        }
    }

    #[pyfunction]
    fn reciprocal(a: PyFloat) -> PyResult<PyFloat> {
        if a == 0.0 {
            Err(MathValueError::new_err("Division by Zero"))
        } else {
            Ok(1.0 / a)
        }
    }

    #[pyfunction]
    fn factorial(a: PyInt) -> PyResult<PyInt> {
        if a < 0 {
            Err(MathValueError::new_err("Negative input not allowed"))
        } else {
            let mut result: PyInt = 1;
            for i in 1..=a {
                result = result.checked_mul(i).ok_or_else(|| {
                    PyErr::new::<PyException, _>("Integer overflow")
                })?;
            }
            Ok(result)
        }
    }

    #[pyfunction]
    /// Berechnet die Summe von `a` und `b`. bei Gleichungen a + b = c
    fn linear_base_c(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(a + b)
    }

    #[pyfunction]
    /// Berechnet `c` minus `a`, um `b` zu isolieren. bei Gleichungen a + b = c
    fn linear_base_b(a: PyFloat, c: PyFloat) -> PyResult<PyFloat> {
        Ok(c - a)
    }

    #[pyfunction]
    /// Berechnet `c` minus `b`, um `a` zu isolieren. bei Gleichungen a + b = c
    fn linear_base_a(b: PyFloat, c: PyFloat) -> PyResult<PyFloat> {
        Ok(c - b)
    }

    #[pyfunction]
    fn sin(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a.sin())
    }

    #[pyfunction]
    fn cos(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a.cos())
    }

    #[pyfunction]
    fn tan(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a.tan())
    }

    #[pyfunction]
    fn asin(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a.asin())
    }

    #[pyfunction]
    fn acos(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a.acos())
    }

    #[pyfunction]
    fn atan(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a.atan())
    }

    #[pyfunction]
    fn arctan(x: PyFloat) -> PyResult<PyFloat> {
        let mut result: PyFloat = 0.0;
        let mut term: PyFloat = x;  // Startterm x^1 / 1
        let mut i: PyInt = 1;

        while term.abs() > 1e-15 {
            if i % 2 == 1 {
                result += term;  // Addiere ungerade Terme
            } else {
                result -= term;  // Subtrahiere gerade Terme
            }
            i += 1;
            term = term * x * x / ((2 * i - 1) as PyFloat) * ((2 * i - 2) as PyFloat);  // Update term zu x^(2i+1) / (2i+1)
        }
        Ok(result)
    }

    #[pyfunction]
    fn calc_pi() -> PyResult<PyFloat> {
        let _a: PyFloat = 1.0 / 2.0;  // Verwende Fließkommadivision
        let _b: PyFloat = 1.0 / 3.0;  // Verwende Fließkommadivision
        let _a1: PyFloat = _a.atan();
        let _b1: PyFloat = _b.atan();
        let _pi_4tel: PyFloat = _a1 + _b1;
        let _pi = 4.0 * _pi_4tel;  // Stelle sicher, dass die Multiplikation mit einem Fließkommawert erfolgt
        Ok(_pi)
    }

    #[pyfunction]
    fn quadratic_base(a: PyFloat, b: PyFloat, c: PyFloat) -> PyResult<(PyFloat, PyFloat)> {
        if a == 0.0 {
            return Err(MathValueError::new_err("Coefficient 'a' must not be zero"));
        }
        let discriminant = b.powf(2.0) - 4.0 * a * c;
        if discriminant.is_nan() || discriminant.is_infinite() {
            return Err(MathValueError::new_err("Discriminant calculation resulted in an invalid number"));
        }
        if discriminant < 0.0 {
            let sqrt_discriminant = (-discriminant).sqrt();
            let _result1 = (-b / (2.0 * a)) + (sqrt_discriminant / (2.0 * a));
            let _result2 = (-b / (2.0 * a)) - (sqrt_discriminant / (2.0 * a));
            if _result1.is_nan() || _result1.is_infinite() || _result2.is_nan() || _result2.is_infinite() {
                return Err(MathValueError::new_err("Result calculation resulted in an invalid number"));
            }
            Ok((_result1, _result2))
        } else {
            let sqrt_discriminant = discriminant.sqrt();
            let _result1 = (-b + sqrt_discriminant) / (2.0 * a);
            let _result2 = (-b - sqrt_discriminant) / (2.0 * a);
            if _result1.is_nan() || _result1.is_infinite() || _result2.is_nan() || _result2.is_infinite() {
                return Err(MathValueError::new_err("Result calculation resulted in an invalid number"));
            }
            Ok((_result1, _result2))
        }
    }

    #[pyfunction]
    fn quadratic_pq(p: PyFloat, q: PyFloat) -> PyResult<(PyFloat, PyFloat)> {
        let discriminant = (p / 2.0).powf(2.0) - q;
        if discriminant.is_nan() || discriminant.is_infinite() {
            return Err(MathValueError::new_err("Discriminant calculation resulted in an invalid number"));
        }
        if discriminant < 0.0 {
            let sqrt_discriminant = (-discriminant).sqrt();
            let _result1 = -(p / 2.0) + sqrt_discriminant;
            let _result2 = -(p / 2.0) - sqrt_discriminant;
            if _result1.is_nan() || _result1.is_infinite() || _result2.is_nan() || _result2.is_infinite() {
                return Err(MathValueError::new_err("Result calculation resulted in an invalid number"));
            }
            Ok((_result1, _result2))
        } else {
            let sqrt_discriminant = discriminant.sqrt();
            let _result1 = -(p / 2.0) + sqrt_discriminant;
            let _result2 = -(p / 2.0) - sqrt_discriminant;
            if _result1.is_nan() || _result1.is_infinite() || _result2.is_nan() || _result2.is_infinite() {
                return Err(MathValueError::new_err("Result calculation resulted in an invalid number"));
            }
            Ok((_result1, _result2))
        }
    }

    #[pyfunction]
    fn rectangle_area(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(a * b)
    }

    #[pyfunction]
    fn rectangle_circumference(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(2.0 * (a + b))
    }

    #[pyfunction]
    fn quadratic_area(a: PyFloat) -> PyResult<PyFloat> {
        Ok(a * a)
    }

    #[pyfunction]
    fn quadratic_circumference(a: PyFloat) -> PyResult<PyFloat> {
        Ok(4.0 * a)
    }

    #[pyfunction]
    fn circle_area(r: PyFloat) -> PyResult<PyFloat> {
        let _a: PyFloat = 1.0 / 2.0;  // Verwende Fließkommadivision
        let _b: PyFloat = 1.0 / 3.0;  // Verwende Fließkommadivision
        let _c: PyFloat = _a.atan() + _b.atan();
        let _pi: PyFloat = 4.0 * _c;
        let _result: PyFloat = _pi * r * r;
        Ok(_result)
    }

    #[pyfunction]
    fn circle_circumference(r: PyFloat) -> PyResult<PyFloat> {
        let _a: PyFloat = 1.0 / 2.0;  // Verwende Fließkommadivision
        let _b: PyFloat = 1.0 / 3.0;  // Verwende Fließkommadivision
        let _c: PyFloat = _a.atan() + _b.atan();
        let _pi: PyFloat = 4.0 * _c;
        let _result: PyFloat = 2.0 * _pi * r;
        Ok(_result)
    }

    #[pyfunction]
    fn trapezoid_area(a: PyFloat, b: PyFloat, h: PyFloat) -> PyResult<PyFloat> {
        Ok((a + b) * h / 2.0)
    }

    #[pyfunction]
    fn trapezoid_circumference(a: PyFloat, b: PyFloat, c: PyFloat, d: PyFloat) -> PyResult<PyFloat> {
        Ok(a + b + c + d)
    }

    #[pyfunction]
    fn parallelogram_area(a: PyFloat, h: PyFloat) -> PyResult<PyFloat> {
        Ok(a * h)
    }

    #[pyfunction]
    fn parallelogram_circumference(a: PyFloat, b: PyFloat) -> PyResult<PyFloat> {
        Ok(2.0 * (a + b))
    }

    /// A Python module implemented in Rust.
    #[pymodule]
    fn highpymath(m: &PyModule) -> PyResult<()> {
        m.add_function(wrap_pyfunction!(sum, m)?)?;
        m.add_function(wrap_pyfunction!(sub, m)?)?;
        m.add_function(wrap_pyfunction!(mul, m)?)?;
        m.add_function(wrap_pyfunction!(div, m)?)?;
        m.add_function(wrap_pyfunction!(exp, m)?)?;
        m.add_function(wrap_pyfunction!(exp2, m)?)?;
        m.add_function(wrap_pyfunction!(sqrt, m)?)?;
        m.add_function(wrap_pyfunction!(sqrt2, m)?)?;
        m.add_function(wrap_pyfunction!(log, m)?)?;
        m.add_function(wrap_pyfunction!(factorial, m)?)?;
        m.add_function(wrap_pyfunction!(reciprocal, m)?)?;
        m.add_function(wrap_pyfunction!(linear_base_c, m)?)?;
        m.add_function(wrap_pyfunction!(linear_base_b, m)?)?;
        m.add_function(wrap_pyfunction!(linear_base_a, m)?)?;
        m.add_function(wrap_pyfunction!(sin, m)?)?;
        m.add_function(wrap_pyfunction!(cos, m)?)?;
        m.add_function(wrap_pyfunction!(tan, m)?)?;
        m.add_function(wrap_pyfunction!(asin, m)?)?;
        m.add_function(wrap_pyfunction!(acos, m)?)?;
        m.add_function(wrap_pyfunction!(atan, m)?)?;
        m.add_function(wrap_pyfunction!(arctan, m)?)?;
        m.add_function(wrap_pyfunction!(calc_pi, m)?)?;
        m.add_function(wrap_pyfunction!(quadratic_base, m)?)?;
        m.add_function(wrap_pyfunction!(quadratic_pq, m)?)?;
        m.add_function(wrap_pyfunction!(rectangle_area, m)?)?;
        m.add_function(wrap_pyfunction!(rectangle_circumference, m)?)?;
        m.add_function(wrap_pyfunction!(quadratic_area, m)?)?;
        m.add_function(wrap_pyfunction!(quadratic_circumference, m)?)?;
        m.add_function(wrap_pyfunction!(circle_area, m)?)?;
        m.add_function(wrap_pyfunction!(circle_circumference, m)?)?;
        m.add_function(wrap_pyfunction!(trapezoid_area, m)?)?;
        m.add_function(wrap_pyfunction!(trapezoid_circumference, m)?)?;
        m.add_function(wrap_pyfunction!(parallelogram_area, m)?)?;
        m.add_function(wrap_pyfunction!(parallelogram_circumference, m)?)?;
        m.add("MathTypeError", m.py().get_type::<MathTypeError>())?;
        m.add("MathValueError", m.py().get_type::<MathValueError>())?;  
        m.add("GeometryError", m.py().get_type::<GeometryError>())?;
        Ok(())
    }