v1 0.0.1

Scalar mathematical library for neural networks.
Documentation
use v1::finance::value::*;

#[test]
fn test_cagr_standard_growth() {
    let res = calculate_cagr(144.0, 100.0, 2.0);
    assert!((res - 0.2).abs() < 1e-6);
}

#[test]
fn test_cagr_no_growth() {
    let res = calculate_cagr(100.0, 100.0, 5.0);
    assert_eq!(res, 0.0);
}

#[test]
fn test_cagr_negative_growth() {
    // Инвестиция упала со 100$ до 50$ за 1 период -> CAGR = -50% (-0.5)
    let res = calculate_cagr(50.0, 100.0, 1.0);
    assert!((res - (-0.5)).abs() < 1e-6);
}

#[test]
fn test_cagr_zero_initial_protection() {
    assert_eq!(calculate_cagr(100.0, 0.0, 5.0), 0.0);
}

#[test]
fn test_cagr_negative_initial_protection() {
    assert_eq!(calculate_cagr(100.0, -10.0, 5.0), 0.0);
}

#[test]
fn test_cagr_zero_periods_protection() {
    assert_eq!(calculate_cagr(150.0, 100.0, 0.0), 0.0);
}

#[test]
fn test_cagr_negative_periods_protection() {
    assert_eq!(calculate_cagr(150.0, 100.0, -2.0), 0.0);
}

#[test]
fn test_cagr_zero_final_protection() {
    assert_eq!(calculate_cagr(0.0, 100.0, 4.0), 0.0);
}

#[test]
fn test_cagr_negative_final_protection() {
    assert_eq!(calculate_cagr(-50.0, 100.0, 4.0), 0.0);
}

#[test]
fn test_cagr_fractional_periods() {
    // Полугодичный период (0.5 года): со 100$ до 121$
    let res = calculate_cagr(121.0, 100.0, 0.5);
    assert!((res - 0.4641).abs() < 1e-4);
}

#[test]
fn test_cagr_high_precision() {
    let final_val = 153.42f32;
    let init_val = 102.11f32;
    let periods = 3.45f32;
    
    let res = calculate_cagr(final_val, init_val, periods);
    
    // Рассчитываем эталон здесь же, используя те же типы f32
    let base = final_val / init_val;
    let exp = 1.0f32 / periods;
    let expected = base.powf(exp) - 1.0f32;
    
    // Теперь мы сравниваем с тем, что физически может выдать функция
    // Допуск 0 означает, что результат обязан быть идентичным
    assert_eq!(res, expected);
}

#[test]
fn test_cagr_huge_investment_scale() {
    let res = calculate_cagr(f32::MAX, 1.0, 100.0);
    assert!(res.is_finite() && res > 0.0);
}

#[test]
fn test_cagr_micro_periods() {
    let res = calculate_cagr(100.001, 100.0, f32::MIN_POSITIVE);
    assert!(res.is_infinite() || res.is_nan() || res == 0.0); // Безопасный исход для поднормальных степеней
}

#[test]
fn test_cagr_subnormal_initial() {
    let res = calculate_cagr(1.0, f32::MIN_POSITIVE, 1.0);
    assert!(res > 0.0);
}

#[test]
fn test_cagr_nan_final_value() {
    assert_eq!(calculate_cagr(f32::NAN, 100.0, 2.0), 0.0);
}

#[test]
fn test_cagr_nan_initial_value() {
    assert_eq!(calculate_cagr(150.0, f32::NAN, 2.0), 0.0);
}

#[test]
fn test_cagr_nan_periods() {
    assert_eq!(calculate_cagr(150.0, 100.0, f32::NAN), 0.0);
}

#[test]
fn test_cagr_infinity_periods() {
    let res = calculate_cagr(200.0, 100.0, f32::INFINITY);
    assert_eq!(res, 0.0); // 1 / inf = 0 -> x^0 - 1 = 1 - 1 = 0
}

#[test]
fn test_cagr_infinity_final() {
    let res = calculate_cagr(f32::INFINITY, 100.0, 2.0);
    assert!(res.is_infinite());
}

#[test]
fn test_cagr_doubling_asset() {
    // Удвоение за 1 период -> CAGR обязан быть ровно 1.0 (100%)
    assert_eq!(calculate_cagr(200.0, 100.0, 1.0), 1.0);
}

#[test]
fn test_cagr_halving_asset() {
    // Падение в два раза за 1 период -> CAGR обязан быть ровно -0.5 (-50%)
    assert_eq!(calculate_cagr(50.0, 100.0, 1.0), -0.5);
}

#[test]
fn test_cagr_one_extreme_period() {
    let res = calculate_cagr(1000.0, 1.0, 1.0);
    assert_eq!(res, 999.0);
}

#[test]
fn test_cagr_large_rounded_periods() {
    let res = calculate_cagr(2.0, 1.0, 1000000.0);
    assert!(res > 0.0 && res < 1e-5);
}

#[test]
fn test_cagr_identity_match() {
    let v = 123.45;
    assert_eq!(calculate_cagr(v, v, 12.0), 0.0);
}

#[test]
fn test_cagr_monotonically_decreasing_with_periods() {
    let cagr_short = calculate_cagr(200.0, 100.0, 2.0);
    let cagr_long = calculate_cagr(200.0, 100.0, 5.0);
    assert!(cagr_short > cagr_long);
}