uninum 0.1.1

A robust, ergonomic unified number type for Rust with automatic overflow handling, type promotion, and cross-type consistency.
Documentation
//! Scientific and engineering calculation showcase for `uninum`.
//!
//! Run with `cargo run --example scientific` to execute the scenarios.

use uninum::{Number, num};

fn celsius_to_fahrenheit(celsius: Number) -> Number {
    &celsius * num!(9) / num!(5) + num!(32)
}

fn fahrenheit_to_celsius(fahrenheit: Number) -> Number {
    (&fahrenheit - num!(32)) * num!(5) / num!(9)
}

fn celsius_to_kelvin(celsius: Number) -> Number {
    celsius + num!(273.15)
}

fn run_temperature_conversions() {
    let c = num!(25.0);
    let f = celsius_to_fahrenheit(c.clone());
    assert!(f.approx_eq(&num!(77.0), 1e-10, 0.0));

    let c2 = fahrenheit_to_celsius(num!(32.0));
    assert!(c2.approx_eq(&num!(0.0), 1e-10, 0.0));

    let k = celsius_to_kelvin(num!(0.0));
    assert!(k.approx_eq(&num!(273.15), 1e-10, 0.0));

    println!("Temperature conversions: 25°C -> {f}°F, 0°C -> {k} K");
}

fn dot_product(a: &[Number], b: &[Number]) -> Number {
    assert_eq!(a.len(), b.len(), "Vectors must have same length");

    a.iter()
        .zip(b.iter())
        .map(|(x, y)| x.clone() * y.clone())
        .reduce(|acc, x| acc + x)
        .unwrap_or_else(|| num!(0))
}

fn vector_magnitude(v: &[Number]) -> Number {
    let sum_of_squares = v
        .iter()
        .map(|x| x.clone() * x.clone())
        .reduce(|acc, x| acc + x)
        .unwrap_or_else(|| num!(0));

    sum_of_squares.sqrt()
}

fn run_vector_operations() {
    let v1 = vec![num!(1), num!(2), num!(3)];
    let v2 = vec![num!(4.0), num!(5.0), num!(6.0)];

    let result = dot_product(&v1, &v2);
    assert!(result.approx_eq(&num!(32.0), 1e-10, 0.0));

    let magnitude = vector_magnitude(&v1);
    let expected_magnitude = num!(14.0_f64.sqrt());
    assert!(magnitude.approx_eq(&expected_magnitude, 1e-10, 0.0));

    println!("Vector operations: dot={result}, |v1|≈{magnitude}");
}

fn kinetic_energy(mass: Number, velocity: Number) -> Number {
    num!(0.5) * &mass * velocity.pow(&num!(2))
}

fn potential_energy(mass: Number, height: Number) -> Number {
    let gravity = num!(9.81);
    &mass * &gravity * &height
}

fn force(mass: Number, acceleration: Number) -> Number {
    mass * acceleration
}

fn run_physics_calculations() {
    let mass = num!(10.0);
    let velocity = num!(5.0);
    let height = num!(2.0);
    let acceleration = num!(2.0);

    let ke = kinetic_energy(mass.clone(), velocity);
    let pe = potential_energy(mass.clone(), height);
    let f = force(mass, acceleration);

    assert!(ke.approx_eq(&num!(125.0), 1e-10, 0.0));
    assert!(pe.approx_eq(&num!(196.2), 1e-10, 0.0));
    assert!(f.approx_eq(&num!(20.0), 1e-10, 0.0));
    assert!(ke.is_finite() && pe.is_finite() && f.is_finite());

    println!("Physics calculations: KE={ke}, PE={pe}, F={f}");
}

fn voltage(current: Number, resistance: Number) -> Number {
    current * resistance
}

fn power(voltage: Number, current: Number) -> Number {
    voltage * current
}

fn power_from_resistance(current: Number, resistance: Number) -> Number {
    let voltage = voltage(current.clone(), resistance);
    power(voltage, current)
}

fn run_electrical_calculations() {
    let current = num!(2.0);
    let resistance = num!(5.0);

    let v = voltage(current.clone(), resistance.clone());
    let p = power_from_resistance(current, resistance);

    assert!(v.approx_eq(&num!(10.0), 1e-10, 0.0));
    assert!(p.approx_eq(&num!(20.0), 1e-10, 0.0));
    assert!(v.is_positive() && p.is_positive());

    println!("Electrical calculations: voltage={v}, power={p}");
}

fn pressure_from_gas_law(volume: Number, moles: Number, temperature: Number) -> Number {
    let gas_constant = num!(0.08314);
    &moles * &gas_constant * &temperature / &volume
}

fn run_chemistry_calculations() {
    let volume = num!(10.0);
    let moles = num!(2.0);
    let temperature = num!(298.15);

    let pressure = pressure_from_gas_law(volume, moles, temperature);
    let expected = num!(4.95782);
    assert!(
        pressure.approx_eq(&expected, 1e-10, 0.0),
        "Ideal gas law calculation error"
    );
    println!("Chemistry calculation: pressure ≈ {pressure} bar");
}

fn main() {
    run_temperature_conversions();
    run_vector_operations();
    run_physics_calculations();
    run_electrical_calculations();
    run_chemistry_calculations();
    println!("Scientific examples completed successfully.");
}