mod error;
pub use error::SqrtError;
use anyhow::Result;
use tokio::task;
pub async fn square_root_async(number: f64) -> Result<f64> {
task::spawn_blocking(move || {
if number < 0.0 {
return Err(SqrtError::NegativeNumber(number))?;
}
let mut guess = number / 2.0;
let mut prev_guess;
loop {
prev_guess = guess;
guess = (guess + number / guess) / 2.0;
if (prev_guess - guess).abs() < 1e-10 {
break;
}
}
Ok(guess)
})
.await?
}
pub async fn square_roots_parallel(numbers: Vec<f64>) -> Result<Vec<f64>> {
task::spawn_blocking(move || {
numbers
.into_iter()
.map(|number| {
if number < 0.0 {
return Err(SqrtError::NegativeNumber(number))?;
}
let mut guess = number / 2.0;
let mut prev_guess;
loop {
prev_guess = guess;
guess = (guess + number / guess) / 2.0;
if (prev_guess - guess).abs() < 1e-10 {
break;
}
}
Ok(guess)
})
.collect()
})
.await?
}
pub fn square_root(number: f64) -> Result<f64> {
if number < 0.0 {
return Err(SqrtError::NegativeNumber(number))?;
}
let mut guess = number / 2.0;
let mut prev_guess;
loop {
prev_guess = guess;
guess = (guess + number / guess) / 2.0;
if (prev_guess - guess).abs() < 1e-10 {
break;
}
}
Ok(guess)
}
pub fn square_roots_parallel_sync(numbers: Vec<f64>) -> Result<Vec<f64>> {
numbers
.into_iter()
.map(|number| {
if number < 0.0 {
return Err(SqrtError::NegativeNumber(number))?;
}
let mut guess = number / 2.0;
let mut prev_guess;
loop {
prev_guess = guess;
guess = (guess + number / guess) / 2.0;
if (prev_guess - guess).abs() < 1e-10 {
break;
}
}
Ok(guess)
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
use tokio::runtime::Runtime;
#[test]
fn test_square_root_async() -> Result<()> {
let rt = Runtime::new().unwrap();
let result = rt.block_on(square_root_async(9.0))?;
assert!((result - 3.0).abs() < 1e-10);
Ok(())
}
#[test]
fn test_square_roots_parallel() -> Result<()> {
let rt = Runtime::new().unwrap();
let numbers = vec![4.0, 16.0, 25.0];
let results = rt.block_on(square_roots_parallel(numbers))?;
let expected = [2.0, 4.0, 5.0];
for (result, &expected_value) in results.iter().zip(expected.iter()) {
assert!((*result - expected_value).abs() < 1e-10);
}
Ok(())
}
#[test]
fn test_square_root_async_negative() {
let rt = Runtime::new().unwrap();
let result = rt.block_on(square_root_async(-4.0));
assert!(result.is_err());
let error_message = result.unwrap_err().to_string();
assert_eq!(
error_message,
"Cannot calculate the square root of a negative number: -4"
);
}
#[test]
fn test_square_roots_parallel_with_negative() {
let rt = Runtime::new().unwrap();
let numbers = vec![4.0, -16.0, 25.0];
let result = rt.block_on(square_roots_parallel(numbers));
assert!(result.is_err());
let error_message = result.unwrap_err().to_string();
assert_eq!(
error_message,
"Cannot calculate the square root of a negative number: -16"
);
}
}
#[cfg(test)]
mod tests_sync {
use super::*;
#[test]
fn test_square_root_sync() -> Result<()> {
let result = square_root(9.0)?;
assert!((result - 3.0).abs() < 1e-10);
Ok(())
}
#[test]
fn test_square_roots_parallel_sync() -> Result<()> {
let numbers = vec![4.0, 16.0, 25.0];
let results = square_roots_parallel_sync(numbers)?;
let expected = [2.0, 4.0, 5.0];
for (result, &expected_value) in results.iter().zip(expected.iter()) {
assert!((*result - expected_value).abs() < 1e-10);
}
Ok(())
}
#[test]
fn test_square_root_sync_negative() {
let result = square_root(-4.0);
assert!(result.is_err());
let error_message = result.unwrap_err().to_string();
assert_eq!(
error_message,
"Cannot calculate the square root of a negative number: -4"
);
}
#[test]
fn test_square_roots_parallel_sync_with_negative() {
let numbers = vec![4.0, -16.0, 25.0];
let result = square_roots_parallel_sync(numbers);
assert!(result.is_err());
let error_message = result.unwrap_err().to_string();
assert_eq!(
error_message,
"Cannot calculate the square root of a negative number: -16"
);
}
}