use uninum::{Number, num};
fn calculate_average(values: &[Number]) -> Number {
if values.is_empty() {
return num!(0);
}
let sum = values.iter().cloned().reduce(|a, b| a + b).unwrap();
let count = num!(values.len());
sum / count
}
fn calculate_weighted_average(values: &[(Number, Number)]) -> Number {
if values.is_empty() {
return num!(0);
}
let weighted_sum = values
.iter()
.map(|(value, weight)| value.clone() * weight.clone())
.reduce(|a, b| a + b)
.unwrap();
let total_weight = values
.iter()
.map(|(_, weight)| weight.clone())
.reduce(|a, b| a + b)
.unwrap();
weighted_sum / total_weight
}
fn analyze_mixed_type_data() {
let values = vec![num!(10), num!(20.5), num!(30), num!(15)];
let avg = calculate_average(&values);
let expected = num!(18.875);
assert!(
avg.approx_eq(&expected, 1e-10, 0.0),
"Mixed type average calculation error: expected {expected}, got {avg}"
);
let weighted_data = vec![
(num!(85.0), num!(0.3)),
(num!(92.0), num!(0.4)),
(num!(78.0), num!(0.3)),
];
let weighted_avg = calculate_weighted_average(&weighted_data);
let expected_weighted = num!(85.7);
assert!(
weighted_avg.approx_eq(&expected_weighted, 1e-10, 0.0),
"Weighted average calculation error: expected {expected_weighted}, got {weighted_avg}"
);
let total_weight = weighted_data
.iter()
.map(|(_, weight)| weight.clone())
.reduce(|a, b| a + b)
.unwrap();
assert!(
total_weight.approx_eq(&num!(1.0), 1e-10, 0.0),
"Weights should sum to 1.0 for proper weighted average"
);
println!("Mixed-type averages: mean={avg}, weighted={weighted_avg}");
}
fn calculate_moving_average(data: &[Number], window_size: usize) -> Vec<Number> {
if window_size == 0 || window_size > data.len() {
return vec![];
}
let mut result = Vec::new();
for window in data.windows(window_size) {
let sum = window.iter().cloned().reduce(|a, b| a + b).unwrap();
let count = Number::from(window_size as u64);
result.push(sum / count);
}
result
}
fn calculate_growth_rate(current: Number, previous: Number) -> Number {
if previous.is_zero() {
return num!(0.0);
}
(¤t - &previous) / &previous * num!(100.0)
}
fn analyze_time_series() {
let prices = vec![
num!(100.0),
num!(105.0),
num!(102.0),
num!(108.0),
num!(110.0),
num!(107.0),
];
let moving_avg = calculate_moving_average(&prices, 3);
assert_eq!(moving_avg.len(), 4);
if let Some(f) = moving_avg[0].try_get_f64() {
assert!((f - 102.333).abs() < 0.01);
} else {
#[cfg(feature = "decimal")]
{
if moving_avg[0].try_get_decimal().is_some() {
assert!(moving_avg[0].approx_eq(&num!(102.333), 0.01, 0.0));
} else {
panic!("Expected F64 or Decimal, got {:?}", moving_avg[0]);
}
}
#[cfg(not(feature = "decimal"))]
{
panic!("Expected F64, got {:?}", moving_avg[0]);
}
}
let growth_rates: Vec<Number> = prices
.windows(2)
.map(|window| calculate_growth_rate(window[1].clone(), window[0].clone()))
.collect();
assert_eq!(growth_rates[0], num!(5.0));
println!(
"Time-series analytics: first moving average = {}, first growth = {}%",
moving_avg[0], growth_rates[0]
);
}
struct SalesRecord {
product_id: u32,
quantity: Number,
unit_price: Number,
discount_rate: Number,
}
impl SalesRecord {
fn total_revenue(&self) -> Number {
let gross = &self.quantity * &self.unit_price;
let discount = gross.clone() * &self.discount_rate;
gross - discount
}
}
fn analyze_sales() {
let records = vec![
SalesRecord {
product_id: 1,
quantity: num!(10),
unit_price: num!(19.99),
discount_rate: num!(0.10),
},
SalesRecord {
product_id: 2,
quantity: num!(5),
unit_price: num!(49.99),
discount_rate: num!(0.0),
},
SalesRecord {
product_id: 3,
quantity: num!(3),
unit_price: num!(99.95),
discount_rate: num!(0.15),
},
];
let mut total_revenue = num!(0);
for record in &records {
let revenue = record.total_revenue();
println!("Product {} revenue: {revenue}", record.product_id);
total_revenue = total_revenue + revenue;
}
let expected = num!(672.3675);
assert!(
total_revenue.approx_eq(&expected, 1e-10, 0.0),
"Sales analytics total mismatch: expected {expected}, got {total_revenue}"
);
println!("Total revenue after discounts: {total_revenue}");
}
fn main() {
analyze_mixed_type_data();
analyze_time_series();
analyze_sales();
println!("Data processing examples completed successfully.");
}