Merge pull request 'pi-day' (#8) from pi-day into develop
Gitea Actions For Fabelous-Math / Explore-Gitea-Actions (push) Successful in 18s
Details
Gitea Actions For Fabelous-Math / Explore-Gitea-Actions (push) Successful in 18s
Details
Reviewed-on: #8
This commit is contained in:
commit
1d0e1dd7e8
|
@ -34,4 +34,4 @@ jobs:
|
|||
VECTORDB_TOKEN: ${{ secrets.VECTORDB_TOKEN }}
|
||||
run: |
|
||||
cd VectorLoader
|
||||
python -m src.run --full
|
||||
python -m src.run
|
||||
|
|
13
README.md
13
README.md
|
@ -17,14 +17,21 @@ pip install git+https://gitea.fabelous.app/Fabel/fabelous-math.git
|
|||
To use the functions provided by Fabelous Math in your Python code, you can import them as follows:
|
||||
|
||||
```python
|
||||
from fabelous_math import is_even, is_odd
|
||||
from fabelous_math import is_even, is_odd, rooting, approximate_pi
|
||||
|
||||
# Example usage:
|
||||
number = 42
|
||||
print(f"Is {number} even? {is_even(number)}")
|
||||
print(f"Is {number} odd? {is_odd(number)}")
|
||||
```
|
||||
|
||||
# Extended feature for rooting with a specified root
|
||||
root = 4
|
||||
number = 16
|
||||
print(f"Rooting {number} to the power of {root}: {rooting(number, root)}")
|
||||
|
||||
# Extended feature for approximate_pi with additional parameters if needed
|
||||
precision = 10000000
|
||||
print(f"Approximate Pi with precision {precision}: {approximate_pi(precision)}")
|
||||
```
|
||||
## Performance Comparison
|
||||
|
||||
To understand the performance of `fabelous-math` functions, I conducted a series of tests comparing my methods with traditional modulo operations. Below are the results:
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 930 B |
Binary file not shown.
After Width: | Height: | Size: 949 B |
Binary file not shown.
After Width: | Height: | Size: 492 B |
|
@ -0,0 +1,61 @@
|
|||
## Approximating Pi Using Numerical Summation
|
||||
|
||||
### Explanation
|
||||
This method approximates the value of \( \pi \) using a numerical summation technique. The approach is based on the concept of inscribing and circumscribing rectangles under a quarter-circle to estimate the area. By summing the areas of these rectangles, we can approximate the area of the quarter-circle, which in turn helps us estimate \( \pi \).
|
||||
|
||||
### Mathematical Representation
|
||||
The equation used is:
|
||||
|
||||

|
||||
|
||||
Where:
|
||||
- \( a \) and \( b \) are summations that approximate the quarter-circle area.
|
||||
- The sum iterates over a set of discrete steps to refine the approximation.
|
||||
|
||||
More specifically, \( a \) and \( b \) are defined as:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
### Python Equivalent
|
||||
|
||||
```python file.py
|
||||
import math
|
||||
|
||||
def approximate_pi(n=46325):
|
||||
lange = n - 2
|
||||
a, b = 0, 0
|
||||
|
||||
# Compute summation for 'a'
|
||||
for k in range(1, lange + 1): # Changed to include lange
|
||||
a += math.sqrt(n**2 - k**2)
|
||||
|
||||
# Compute summation for 'b'
|
||||
for j in range(lange + 1): # Changed to include lange
|
||||
b += math.sqrt(n**2 - j**2)
|
||||
|
||||
# Normalize the results
|
||||
b = 4 / (n**2) * b
|
||||
a = 4 / (n**2) * a
|
||||
result = (a + b) / 2
|
||||
|
||||
return result
|
||||
|
||||
# Run the function
|
||||
print(approximate_pi())
|
||||
```
|
||||
|
||||
### How It Works
|
||||
1. **Initialization**: The variable `lange` is set to \( n - 2 \), and two summation variables `a` and `b` are initialized to zero.
|
||||
2. **Summation for 'a'**: Iterates from 1 to `lange`, calculating the square root of \( n^2 - k^2 \) for each \( k \).
|
||||
3. **Summation for 'b'**: Iterates from 0 to `lange`, calculating the square root of \( n^2 - j^2 \) for each \( j \).
|
||||
4. **Normalization**: Both summations are normalized by multiplying by \( \frac{4}{n^2} \).
|
||||
5. **Result Calculation**: The final approximation of \( \pi \) is obtained by averaging the normalized values of `a` and `b`.
|
||||
|
||||
### Conclusion
|
||||
This method provides an approximation of \( \pi \) using numerical summation. The accuracy increases as \( n \) grows larger, effectively refining the result. By adjusting the value of \( n \), you can control the trade-off between computational effort and precision.
|
||||
|
||||
### Notes
|
||||
- The choice of `n = 46325` is arbitrary and can be adjusted for better performance or higher precision.
|
||||
- This method is computationally intensive and may require optimization for very large values of \( n \).
|
16
example.py
16
example.py
|
@ -1,4 +1,14 @@
|
|||
from fabelous_math import is_even, is_odd
|
||||
from fabelous_math import is_even, is_odd, rooting, approximate_pi
|
||||
|
||||
print(is_even(5))
|
||||
print(is_odd(19))
|
||||
number = 42
|
||||
print(f"Is {number} even? {is_even(number)}")
|
||||
print(f"Is {number} odd? {is_odd(number)}")
|
||||
|
||||
# Extended feature for rooting with a specified root
|
||||
root = 4
|
||||
number = 16
|
||||
print(f"Rooting {number} to the power of {root}: {rooting(number, root)}")
|
||||
|
||||
# Extended feature for approximate_pi with additional parameters if needed
|
||||
precision = 10000000
|
||||
print(f"Approximate Pi with precision {precision}: {approximate_pi(precision)}")
|
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||
|
||||
[project]
|
||||
name = "fabelous_math"
|
||||
version = "0.0.1"
|
||||
version = "0.3.141"
|
||||
description = "Math functions written in C++ for faster code"
|
||||
authors = [
|
||||
{name = "Falko Habel", email = "falko.habel@fabelous.app"}
|
||||
|
|
28
setup.py
28
setup.py
|
@ -10,11 +10,33 @@ if platform.system() == "Windows":
|
|||
else:
|
||||
extra_compile_args.append('-std=c++17')
|
||||
|
||||
module = Extension(
|
||||
simple_functions_module = Extension(
|
||||
'fabelous_math.simple_functions',
|
||||
sources=[
|
||||
'src/fabelous_math/cpp/functions/simple_functions.cpp',
|
||||
'src/fabelous_math/cpp/functions/bindings.cpp'
|
||||
'src/fabelous_math/cpp/functions/bindings/simple_functions_bindings.cpp'
|
||||
],
|
||||
include_dirs=['src/fabelous_math/include'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
extra_link_args=extra_link_args,
|
||||
)
|
||||
|
||||
pi_module = Extension(
|
||||
'fabelous_math.pi',
|
||||
sources=[
|
||||
'src/fabelous_math/cpp/functions/pi.cpp',
|
||||
'src/fabelous_math/cpp/functions/bindings/pi_bindings.cpp'
|
||||
],
|
||||
include_dirs=['src/fabelous_math/include'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
extra_link_args=extra_link_args,
|
||||
)
|
||||
|
||||
sqrt_module = Extension(
|
||||
'fabelous_math.rooting',
|
||||
sources=[
|
||||
'src/fabelous_math/cpp/functions/rooting.cpp',
|
||||
'src/fabelous_math/cpp/functions/bindings/rooting_bindings.cpp'
|
||||
],
|
||||
include_dirs=['src/fabelous_math/include'],
|
||||
extra_compile_args=extra_compile_args,
|
||||
|
@ -24,7 +46,7 @@ module = Extension(
|
|||
setup(
|
||||
name='fabelous_math',
|
||||
description='Math functions written in C++ for faster code',
|
||||
ext_modules=[module],
|
||||
ext_modules=[simple_functions_module, sqrt_module, pi_module],
|
||||
author="Falko Habel",
|
||||
author_email="falko.habel@fabelous.app"
|
||||
)
|
|
@ -1,3 +1,5 @@
|
|||
from fabelous_math.simple_functions import is_even, is_odd
|
||||
from fabelous_math.pi import approximate_pi
|
||||
from fabelous_math.rooting import rooting
|
||||
|
||||
__all__ = ["is_even", "is_odd"]
|
||||
__all__ = ["is_even", "is_odd", "approximate_pi", "rooting"]
|
|
@ -0,0 +1,28 @@
|
|||
#include <Python.h>
|
||||
#include "pi.hpp"
|
||||
|
||||
static PyObject* approximate_pi_wrapper(PyObject* self, PyObject* args) {
|
||||
long long number;
|
||||
if (!PyArg_ParseTuple(args, "L", &number)) { // Changed to 'L' for long long
|
||||
return NULL;
|
||||
}
|
||||
double result = pi::approximate_pi(number); // Change to double
|
||||
return PyFloat_FromDouble(result); // Return the actual result as a float
|
||||
}
|
||||
|
||||
static PyMethodDef PiMethods[] = {
|
||||
{"approximate_pi", approximate_pi_wrapper, METH_VARARGS, "Calculate the approximation of pi"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef pi_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"pi",
|
||||
"Module for calculating the approximation of pi",
|
||||
-1,
|
||||
PiMethods
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_pi(void) {
|
||||
return PyModule_Create(&pi_module);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#include <Python.h>
|
||||
#include "rooting.hpp"
|
||||
#include <stdexcept>
|
||||
|
||||
static PyObject* rooting_wrapper(PyObject* self, PyObject* args) {
|
||||
double number; // Changed to double to accept floating-point numbers
|
||||
double n = 2.0; // Default value for the second argument
|
||||
|
||||
if (!PyArg_ParseTuple(args, "d|d", &number, &n)) { // First arg required, second optional
|
||||
return NULL;
|
||||
}
|
||||
|
||||
try {
|
||||
double result = rooting::nth_root(number, n); // Pass number directly as double
|
||||
return PyFloat_FromDouble(result);
|
||||
} catch (const std::invalid_argument& e) {
|
||||
PyErr_SetString(PyExc_ValueError, e.what());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyMethodDef NthRootMethods[] = {
|
||||
{"rooting", rooting_wrapper, METH_VARARGS, "Compute the nth root of a number"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef sqrt_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"fabelous_math.rooting",
|
||||
"Module for computing the nth root of a number",
|
||||
-1,
|
||||
NthRootMethods
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_rooting(void) {
|
||||
return PyModule_Create(&sqrt_module);
|
||||
}
|
|
@ -17,20 +17,20 @@ static PyObject* is_odd_wrapper(PyObject* self, PyObject* args) {
|
|||
return PyBool_FromLong(simple_functions::is_odd(number));
|
||||
}
|
||||
|
||||
static PyMethodDef NumberUtilsMethods[] = {
|
||||
static PyMethodDef SimpleFunctionsMethods[] = {
|
||||
{"is_even", is_even_wrapper, METH_VARARGS, "Check if a number is even"},
|
||||
{"is_odd", is_odd_wrapper, METH_VARARGS, "Check if a number is odd"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef number_utils_module = {
|
||||
static struct PyModuleDef simple_functions_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"simple_functions",
|
||||
"Module for checking if numbers are even or odd",
|
||||
-1,
|
||||
NumberUtilsMethods
|
||||
SimpleFunctionsMethods
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_simple_functions(void) {
|
||||
return PyModule_Create(&number_utils_module);
|
||||
}
|
||||
return PyModule_Create(&simple_functions_module);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#include "pi.hpp"
|
||||
#include <cmath>
|
||||
#include <iostream> // Include iostream for debugging
|
||||
|
||||
long double pi::approximate_pi(long long number) {
|
||||
long long lange = number - 2;
|
||||
long double a = 0, b = 0;
|
||||
|
||||
// Compute summation for 'a'
|
||||
for (long long k = 1; k <= lange; ++k) { // Changed to include lange
|
||||
long double value = std::sqrt(number * number - k * k);
|
||||
a += value;
|
||||
}
|
||||
|
||||
// Compute summation for 'b'
|
||||
for (long long j = 0; j <= lange; ++j) { // Changed to include lange
|
||||
long double value = std::sqrt(number * number - j * j);
|
||||
b += value;
|
||||
}
|
||||
|
||||
// Normalize the results
|
||||
b = 4.0 / (number * number) * b;
|
||||
a = 4.0 / (number * number) * a;
|
||||
|
||||
long double result = (a + b) / 2;
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#include "rooting.hpp"
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <limits>
|
||||
|
||||
double rooting::nth_root(long double number, double n) {
|
||||
// Special case handling
|
||||
if (n <= 0) {
|
||||
throw std::invalid_argument("The root must be positive and non-zero");
|
||||
}
|
||||
|
||||
if (number < 0 && std::fmod(n, 2.0) == 0) {
|
||||
throw std::invalid_argument("Cannot compute even root of a negative number");
|
||||
}
|
||||
|
||||
if (number == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if (number == 1 || n == 1.0) {
|
||||
return number;
|
||||
}
|
||||
|
||||
// Handle negative numbers for odd roots
|
||||
bool negative = number < 0;
|
||||
double abs_number = negative ? -number : number;
|
||||
|
||||
// Use logarithm method for initial guess
|
||||
double log_result = std::log(abs_number) / n;
|
||||
double x = std::exp(log_result);
|
||||
|
||||
// Constants
|
||||
const double epsilon = 1e-15;
|
||||
const int max_iterations = 100;
|
||||
|
||||
// Newton-Raphson method
|
||||
for (int i = 0; i < max_iterations; i++) {
|
||||
double x_prev = x;
|
||||
|
||||
// Calculate new approximation, handling potential overflow
|
||||
double x_pow = std::pow(x, n - 1);
|
||||
|
||||
// Prevent division by zero
|
||||
if (x_pow < std::numeric_limits<double>::min()) {
|
||||
break;
|
||||
}
|
||||
|
||||
x = ((n - 1) * x + abs_number / x_pow) / n;
|
||||
|
||||
// Check for convergence using relative error
|
||||
if (std::fabs(x - x_prev) <= epsilon * std::fabs(x)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return correct sign for odd roots of negative numbers
|
||||
return negative ? -x : x;
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
#include "simple_functions.hpp"
|
||||
|
||||
namespace simple_functions {
|
||||
bool is_even(long long number) {
|
||||
return (number & 1) == 0;
|
||||
}
|
||||
bool simple_functions::is_even(long long number) {
|
||||
return (number & 1) == 0;
|
||||
}
|
||||
|
||||
bool is_odd(long long number) {
|
||||
return (number & 1);
|
||||
}
|
||||
}
|
||||
bool simple_functions::is_odd(long long number) {
|
||||
return (number & 1);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
namespace pi {
|
||||
long double approximate_pi(long long number);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
namespace rooting {
|
||||
double nth_root(long double number, double n);
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import pytest
|
||||
from fabelous_math import approximate_pi
|
||||
|
||||
def test_approximate_pi():
|
||||
# Test with a known precision value
|
||||
precision = 10000
|
||||
pi_approx = approximate_pi(precision)
|
||||
assert isinstance(pi_approx, float), "The result should be a float"
|
||||
assert pi_approx > 3.14, "The approximation of Pi should be greater than 3.14"
|
||||
assert pi_approx < 3.15, "The approximation of Pi should be less than 3.15"
|
||||
|
||||
def test_approximate_pi_with_low_precision():
|
||||
# Test with a low precision value
|
||||
precision = 100
|
||||
pi_approx = approximate_pi(precision)
|
||||
assert isinstance(pi_approx, float), "The result should be a float"
|
||||
assert pi_approx > 3.0, "The approximation of Pi should be greater than 3.0"
|
||||
assert pi_approx < 4.0, "The approximation of Pi should be less than 4.0"
|
||||
|
||||
def test_approximate_pi_with_high_precision():
|
||||
# Test with a high precision value
|
||||
precision = 10000000
|
||||
pi_approx = approximate_pi(precision)
|
||||
assert isinstance(pi_approx, float), "The result should be a float"
|
||||
assert pi_approx > 3.1415926533, "The approximation of Pi should be greater than the known value of Pi"
|
|
@ -0,0 +1,44 @@
|
|||
import pytest
|
||||
from fabelous_math import rooting
|
||||
import math
|
||||
|
||||
def test_fabelous_sqrt():
|
||||
# Test with a perfect square
|
||||
assert rooting(4) == 2
|
||||
|
||||
# Test with a non-perfect square
|
||||
expected_value = math.sqrt(5)
|
||||
assert abs(rooting(5) - expected_value) < 1e-8
|
||||
|
||||
# Test with zero
|
||||
assert rooting(0) == 0
|
||||
|
||||
# Test with a large number
|
||||
assert abs(rooting(1000000) - 1000) < 1e-8
|
||||
|
||||
# Test with a negative number (should raise ValueError)
|
||||
with pytest.raises(ValueError):
|
||||
rooting(-1)
|
||||
|
||||
def test_fabelous_sqrt_edge_cases():
|
||||
# Test with very small positive number
|
||||
assert abs(rooting(1e-10, 2) - 1e-5) < 1e-8 # For square root
|
||||
|
||||
# Test with very large positive number
|
||||
assert abs(rooting(1e+308) - 1e+154) < 1e-8
|
||||
|
||||
def test_fabelous_sqrt_invalid_input():
|
||||
# Test with non-numeric input (should raise TypeError)
|
||||
with pytest.raises(TypeError):
|
||||
rooting("string")
|
||||
|
||||
# Test with None input (should raise TypeError)
|
||||
with pytest.raises(TypeError):
|
||||
rooting(None)
|
||||
|
||||
def test_fabelous_sqrt_consistency():
|
||||
# Test consistency with known values
|
||||
known_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
for value in known_values:
|
||||
expected_value = math.sqrt(value)
|
||||
assert abs(rooting(value) - expected_value) < 1e-8
|
Loading…
Reference in New Issue