Skip to content

Commit

Permalink
Merge branch 'master' into ref/graph/kruskal
Browse files Browse the repository at this point in the history
  • Loading branch information
vil02 authored Nov 6, 2024
2 parents ae5811d + e92ab20 commit a5b0712
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 9 deletions.
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
* [Subset Generation](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/subset_generation.rs)
* [Trapped Rainwater](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/trapped_rainwater.rs)
* [Word Break](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/word_break.rs)
* Financial
* [Present Value](https://github.com/TheAlgorithms/Rust/blob/master/src/financial/present_value.rs)
* General
* [Convex Hull](https://github.com/TheAlgorithms/Rust/blob/master/src/general/convex_hull.rs)
* [Fisher Yates Shuffle](https://github.com/TheAlgorithms/Rust/blob/master/src/general/fisher_yates_shuffle.rs)
Expand Down
2 changes: 2 additions & 0 deletions src/financial/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod present_value;
pub use present_value::present_value;
91 changes: 91 additions & 0 deletions src/financial/present_value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/// In economics and finance, present value (PV), also known as present discounted value,
/// is the value of an expected income stream determined as of the date of valuation.
///
/// -> Wikipedia reference: https://en.wikipedia.org/wiki/Present_value
#[derive(PartialEq, Eq, Debug)]
pub enum PresentValueError {
NegetiveDiscount,
EmptyCashFlow,
}

pub fn present_value(discount_rate: f64, cash_flows: Vec<f64>) -> Result<f64, PresentValueError> {
if discount_rate < 0.0 {
return Err(PresentValueError::NegetiveDiscount);
}
if cash_flows.is_empty() {
return Err(PresentValueError::EmptyCashFlow);
}

let present_value = cash_flows
.iter()
.enumerate()
.map(|(i, &cash_flow)| cash_flow / (1.0 + discount_rate).powi(i as i32))
.sum::<f64>();

Ok(round(present_value))
}

fn round(value: f64) -> f64 {
(value * 100.0).round() / 100.0
}

#[cfg(test)]
mod tests {
use super::*;

macro_rules! test_present_value {
($($name:ident: $inputs:expr,)*) => {
$(
#[test]
fn $name() {
let ((discount_rate,cash_flows), expected) = $inputs;
assert_eq!(present_value(discount_rate,cash_flows).unwrap(), expected);
}
)*
}
}

macro_rules! test_present_value_Err {
($($name:ident: $inputs:expr,)*) => {
$(
#[test]
fn $name() {
let ((discount_rate,cash_flows), expected) = $inputs;
assert_eq!(present_value(discount_rate,cash_flows).unwrap_err(), expected);
}
)*
}
}

macro_rules! test_round {
($($name:ident: $inputs:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $inputs;
assert_eq!(round(input), expected);
}
)*
}
}

test_present_value! {
general_inputs1:((0.13, vec![10.0, 20.70, -293.0, 297.0]),4.69),
general_inputs2:((0.07, vec![-109129.39, 30923.23, 15098.93, 29734.0, 39.0]),-42739.63),
general_inputs3:((0.07, vec![109129.39, 30923.23, 15098.93, 29734.0, 39.0]), 175519.15),
zero_input:((0.0, vec![109129.39, 30923.23, 15098.93, 29734.0, 39.0]), 184924.55),

}

test_present_value_Err! {
negative_discount_rate:((-1.0, vec![10.0, 20.70, -293.0, 297.0]), PresentValueError::NegetiveDiscount),
empty_cash_flow:((1.0, vec![]), PresentValueError::EmptyCashFlow),

}
test_round! {
test1:(0.55434, 0.55),
test2:(10.453, 10.45),
test3:(1111_f64, 1111_f64),
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod compression;
pub mod conversions;
pub mod data_structures;
pub mod dynamic_programming;
pub mod financial;
pub mod general;
pub mod geometry;
pub mod graph;
Expand Down
68 changes: 59 additions & 9 deletions src/string/palindrome.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,74 @@
//! A module for checking if a given string is a palindrome.
/// Checks if the given string is a palindrome.
///
/// A palindrome is a sequence that reads the same backward as forward.
/// This function ignores non-alphanumeric characters and is case-insensitive.
///
/// # Arguments
///
/// * `s` - A string slice that represents the input to be checked.
///
/// # Returns
///
/// * `true` if the string is a palindrome; otherwise, `false`.
pub fn is_palindrome(s: &str) -> bool {
let mut chars = s.chars();
let mut chars = s
.chars()
.filter(|c| c.is_alphanumeric())
.map(|c| c.to_ascii_lowercase());

while let (Some(c1), Some(c2)) = (chars.next(), chars.next_back()) {
if c1 != c2 {
return false;
}
}

true
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn palindromes() {
assert!(is_palindrome("abcba"));
assert!(is_palindrome("abba"));
assert!(is_palindrome("a"));
assert!(is_palindrome("arcra"));
assert!(!is_palindrome("abcde"));
assert!(!is_palindrome("aaaabbbb"));
macro_rules! palindrome_tests {
($($name:ident: $inputs:expr,)*) => {
$(
#[test]
fn $name() {
let (input, expected) = $inputs;
assert_eq!(is_palindrome(input), expected);
}
)*
}
}

palindrome_tests! {
odd_palindrome: ("madam", true),
even_palindrome: ("deified", true),
single_character_palindrome: ("x", true),
single_word_palindrome: ("eye", true),
case_insensitive_palindrome: ("RaceCar", true),
mixed_case_and_punctuation_palindrome: ("A man, a plan, a canal, Panama!", true),
mixed_case_and_space_palindrome: ("No 'x' in Nixon", true),
empty_string: ("", true),
pompeii_palindrome: ("Roma-Olima-Milo-Amor", true),
napoleon_palindrome: ("Able was I ere I saw Elba", true),
john_taylor_palindrome: ("Lewd did I live, & evil I did dwel", true),
well_know_english_palindrome: ("Never odd or even", true),
palindromic_phrase: ("Rats live on no evil star", true),
names_palindrome: ("Hannah", true),
prime_minister_of_cambodia: ("Lon Nol", true),
japanese_novelist_and_manga_writer: ("Nisio Isin", true),
actor: ("Robert Trebor", true),
rock_vocalist: ("Ola Salo", true),
pokemon_species: ("Girafarig", true),
lychrel_num_56: ("121", true),
universal_palindrome_date: ("02/02/2020", true),
french_palindrome: ("une Slave valse nu", true),
finnish_palindrome: ("saippuakivikauppias", true),
non_palindrome_simple: ("hello", false),
non_palindrome_with_punctuation: ("hello!", false),
non_palindrome_mixed_case: ("Hello, World", false),
}
}

0 comments on commit a5b0712

Please sign in to comment.