Skip to content

Commit

Permalink
Add trigonometric functions (TheAlgorithms#643)
Browse files Browse the repository at this point in the history
  • Loading branch information
mihaubuhai authored Jan 2, 2024
1 parent ebdc7cc commit bcc9e32
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 89 deletions.
2 changes: 1 addition & 1 deletion DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@
* [Interquartile Range](https://github.com/TheAlgorithms/Rust/blob/master/src/math/interquartile_range.rs)
* [Karatsuba Multiplication](https://github.com/TheAlgorithms/Rust/blob/master/src/math/karatsuba_multiplication.rs)
* [Lcm Of N Numbers](https://github.com/TheAlgorithms/Rust/blob/master/src/math/lcm_of_n_numbers.rs)
* [Least Square Approximation](https://github.com/TheAlgorithms/Rust/blob/master/src/math/least_square_approx.rs)
* [Leaky Relu](https://github.com/TheAlgorithms/Rust/blob/master/src/math/leaky_relu.rs)
* [Least Square Approx](https://github.com/TheAlgorithms/Rust/blob/master/src/math/least_square_approx.rs)
* [Linear Sieve](https://github.com/TheAlgorithms/Rust/blob/master/src/math/linear_sieve.rs)
* [Logarithm](https://github.com/TheAlgorithms/Rust/blob/master/src/math/logarithm.rs)
* [Lucas Series](https://github.com/TheAlgorithms/Rust/blob/master/src/math/lucas_series.rs)
Expand Down
44 changes: 29 additions & 15 deletions src/math/least_square_approx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,49 @@
///
/// degree -> degree of the polynomial
///
pub fn least_square_approx(points: &[(f64, f64)], degree: i32) -> Vec<f64> {
pub fn least_square_approx<T: Into<f64> + Copy, U: Into<f64> + Copy>(
points: &[(T, U)],
degree: i32,
) -> Option<Vec<f64>> {
use nalgebra::{DMatrix, DVector};

/* Used for rounding floating numbers */
fn round_to_decimals(value: f64, decimals: u32) -> f64 {
let multiplier = 10f64.powi(decimals as i32);
fn round_to_decimals(value: f64, decimals: i32) -> f64 {
let multiplier = 10f64.powi(decimals);
(value * multiplier).round() / multiplier
}

/* Casting the data parsed to this function to f64 (as some points can have decimals) */
let vals: Vec<(f64, f64)> = points
.iter()
.map(|(x, y)| ((*x).into(), (*y).into()))
.collect();
/* Because of collect we need the Copy Trait for T and U */

/* Computes the sums in the system of equations */
let mut sums = Vec::<f64>::new();
for i in 1..=(2 * degree + 1) {
sums.push(points.iter().map(|(x, _)| x.powi(i - 1)).sum());
sums.push(vals.iter().map(|(x, _)| x.powi(i - 1)).sum());
}

let mut free_col = Vec::<f64>::new();
/* Compute the free terms column vector */
let mut free_col = Vec::<f64>::new();
for i in 1..=(degree + 1) {
free_col.push(points.iter().map(|(x, y)| y * (x.powi(i - 1))).sum());
free_col.push(vals.iter().map(|(x, y)| y * (x.powi(i - 1))).sum());
}
let b = DVector::from_row_slice(&free_col);

let size = (degree + 1) as usize;
/* Create and fill the system's matrix */
let a = DMatrix::from_fn(size, size, |i, j| sums[i + j]);
let size = (degree + 1) as usize;
let a = DMatrix::from_fn(size, size, |i, j| sums[degree as usize + i - j]);

/* Solve the system of equations: A * x = b */
match a.qr().solve(&b) {
Some(x) => {
let mut rez: Vec<f64> = x.iter().map(|x| round_to_decimals(*x, 5)).collect();
rez.reverse();
rez
let rez: Vec<f64> = x.iter().map(|x| round_to_decimals(*x, 5)).collect();
Some(rez)
}
None => Vec::new(),
None => None, //<-- The system cannot be solved (badly conditioned system's matrix)
}
}

Expand All @@ -65,7 +74,10 @@ mod tests {
(5.1, 8.4),
];

assert_eq!(least_square_approx(&points, 1), [-0.49069, 10.44898]);
assert_eq!(
least_square_approx(&points, 1),
Some(vec![-0.49069, 10.44898])
);
}

#[test]
Expand All @@ -83,7 +95,9 @@ mod tests {

assert_eq!(
least_square_approx(&points, 5),
[0.00603, -0.21304, 2.79929, -16.53468, 40.29473, -19.35771]
Some(vec![
0.00603, -0.21304, 2.79929, -16.53468, 40.29473, -19.35771
])
);
}

Expand All @@ -96,6 +110,6 @@ mod tests {
(0.7051, 3.49716601),
];

assert_eq!(least_square_approx(&points, 2), [1.0, 0.0, 3.0]);
assert_eq!(least_square_approx(&points, 2), Some(vec![1.0, 0.0, 3.0]));
}
}
27 changes: 14 additions & 13 deletions src/math/logarithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,38 @@ use std::f64::consts::E;
/// Parameters:
/// <p>-> base: base of log
/// <p>-> x: value for which log shall be evaluated
/// <p>-> tol: tolerance; the precision of the approximation
/// <p>-> tol: tolerance; the precision of the approximation (submultiples of 10<sup>-1</sup>)
///
/// Advisable to use **std::f64::consts::*** for specific bases (like 'e')
pub fn log(base: f64, mut x: f64, tol: f64) -> f64 {
pub fn log<T: Into<f64>, U: Into<f64>>(base: U, x: T, tol: f64) -> f64 {
let mut rez: f64 = 0f64;
let mut argument: f64 = x.into();
let usable_base: f64 = base.into();

if x <= 0f64 || base <= 0f64 {
if argument <= 0f64 || usable_base <= 0f64 {
println!("Log does not support negative argument or negative base.");
f64::NAN
} else if x < 1f64 && base == E {
} else if argument < 1f64 && usable_base == E {
argument -= 1f64;
let mut prev_rez = 1f64;
let mut step: i32 = 1;
/*
For x in (0, 1) and base 'e', the function is using MacLaurin Series:
ln(|1 + x|) = Σ "(-1)^n-1 * x^n / n", for n = 1..inf
Substituting x with x-1 yields:
ln(|x|) = Σ "(-1)^n-1 * (x-1)^n / n"
*/
x -= 1f64;

let mut prev_rez = 1f64;
let mut step: i32 = 1;

while (prev_rez - rez).abs() > tol {
prev_rez = rez;
rez += (-1f64).powi(step - 1) * x.powi(step) / step as f64;
rez += (-1f64).powi(step - 1) * argument.powi(step) / step as f64;
step += 1;
}

rez
} else {
let ln_x = x.ln();
let ln_base = base.ln();
/* Using the basic change of base formula for log */
let ln_x = argument.ln();
let ln_base = usable_base.ln();

ln_x / ln_base
}
Expand All @@ -49,7 +50,7 @@ mod test {
fn basic() {
assert_eq!(log(E, E, 0.0), 1.0);
assert_eq!(log(E, E.powi(100), 0.0), 100.0);
assert_eq!(log(10.0, 10000.0, 0.0), 4.0);
assert_eq!(log(10, 10000.0, 0.0), 4.0);
assert_eq!(log(234501.0, 1.0, 1.0), 0.0);
}

Expand Down
11 changes: 9 additions & 2 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ mod sieve_of_eratosthenes;
mod sigmoid;
mod signum;
mod simpson_integration;
mod sine;
mod softmax;
mod sprague_grundy_theorem;
mod square_pyramidal_numbers;
Expand All @@ -72,6 +71,7 @@ mod sylvester_sequence;
mod tanh;
mod trapezoidal_integration;
mod trial_division;
mod trig_functions;
mod vector_cross_product;
mod zellers_congruence_algorithm;

Expand Down Expand Up @@ -145,7 +145,6 @@ pub use self::sieve_of_eratosthenes::sieve_of_eratosthenes;
pub use self::sigmoid::sigmoid;
pub use self::signum::signum;
pub use self::simpson_integration::simpson_integration;
pub use self::sine::sine;
pub use self::softmax::softmax;
pub use self::sprague_grundy_theorem::calculate_grundy_number;
pub use self::square_pyramidal_numbers::square_pyramidal_number;
Expand All @@ -157,6 +156,14 @@ pub use self::sylvester_sequence::sylvester;
pub use self::tanh::tanh;
pub use self::trapezoidal_integration::trapezoidal_integral;
pub use self::trial_division::trial_division;
pub use self::trig_functions::cosine;
pub use self::trig_functions::cosine_no_radian_arg;
pub use self::trig_functions::cotan;
pub use self::trig_functions::cotan_no_radian_arg;
pub use self::trig_functions::sine;
pub use self::trig_functions::sine_no_radian_arg;
pub use self::trig_functions::tan;
pub use self::trig_functions::tan_no_radian_arg;
pub use self::vector_cross_product::cross_product;
pub use self::vector_cross_product::vector_magnitude;
pub use self::zellers_congruence_algorithm::zellers_congruence_algorithm;
58 changes: 0 additions & 58 deletions src/math/sine.rs

This file was deleted.

Loading

0 comments on commit bcc9e32

Please sign in to comment.