use spirix::*;
use std::time::{Duration, Instant};
const PERFORMANCE_ITERATIONS: usize = 10000;
const MAX_OPERATION_NANOS: u128 = 10000;
#[test]
fn test_scalar_arithmetic_performance() {
let values: Vec<ScalarF5E3> = (0..1000)
.map(|i| ScalarF5E3::from(i as f32 * 0.1))
.collect();
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result = values[42] + values[43];
std::hint::black_box(result); }
let addition_time = start.elapsed();
assert!(
addition_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS,
"Addition too slow: {} ns per operation",
addition_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result = values[42] * values[43];
std::hint::black_box(result);
}
let mult_time = start.elapsed();
assert!(
mult_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS,
"Multiplication too slow: {} ns per operation",
mult_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result = values[42] / values[43];
std::hint::black_box(result);
}
let div_time = start.elapsed();
assert!(
div_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS * 5,
"Division too slow: {} ns per operation",
div_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
}
#[test]
fn test_circle_arithmetic_performance() {
let circles: Vec<CircleF5E3> = (0..1000)
.map(|i| CircleF5E3::from((i as f32 * 0.1, i as f32 * 0.2)))
.collect();
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result = circles[42] + circles[43];
std::hint::black_box(result);
}
let addition_time = start.elapsed();
assert!(
addition_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS * 2,
"Complex addition too slow: {} ns per operation",
addition_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result = circles[42] * circles[43];
std::hint::black_box(result);
}
let mult_time = start.elapsed();
assert!(
mult_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS * 8,
"Complex multiplication too slow: {} ns per operation",
mult_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
}
#[test]
fn test_transcendental_function_performance() {
let values: Vec<ScalarF5E3> = (1..1000)
.map(|i| ScalarF5E3::from(i as f32 * 0.01))
.collect();
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS / 10 {
let result = values[42].sin();
std::hint::black_box(result);
}
let sin_time = start.elapsed();
assert!(
sin_time.as_nanos() / ((PERFORMANCE_ITERATIONS / 10) as u128) < MAX_OPERATION_NANOS * 100,
"Sin too slow: {} ns per operation",
sin_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128 / 10)
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS / 10 {
let result = values[42].exp();
std::hint::black_box(result);
}
let exp_time = start.elapsed();
assert!(
exp_time.as_nanos() / ((PERFORMANCE_ITERATIONS / 10) as u128) < MAX_OPERATION_NANOS * 100,
"Exp too slow: {} ns per operation",
exp_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128 / 10)
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS / 10 {
let result = values[42].ln();
std::hint::black_box(result);
}
let ln_time = start.elapsed();
assert!(
ln_time.as_nanos() / ((PERFORMANCE_ITERATIONS / 10) as u128) < MAX_OPERATION_NANOS * 100,
"Ln too slow: {} ns per operation",
ln_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128 / 10)
);
}
#[test]
fn test_conversion_performance() {
let f32_values: Vec<f32> = (0..1000).map(|i| i as f32 * 0.1).collect();
let scalar_values: Vec<ScalarF5E3> = f32_values.iter().map(|&f| ScalarF5E3::from(f)).collect();
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result = ScalarF5E3::from(f32_values[42]);
std::hint::black_box(result);
}
let from_f32_time = start.elapsed();
assert!(
from_f32_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS,
"f32 -> Scalar conversion too slow: {} ns per operation",
from_f32_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let result: f32 = scalar_values[42].into();
std::hint::black_box(result);
}
let to_f32_time = start.elapsed();
assert!(
to_f32_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128) < MAX_OPERATION_NANOS,
"Scalar -> f32 conversion too slow: {} ns per operation",
to_f32_time.as_nanos() / PERFORMANCE_ITERATIONS as u128
);
}
#[test]
fn test_state_checking_performance() {
let values: Vec<ScalarF5E3> = vec![
ScalarF5E3::from(42.0),
ScalarF5E3::ZERO,
ScalarF5E3::INFINITY,
ScalarF5E3::MAX * ScalarF5E3::from(2.0), ScalarF5E3::MIN_POS / ScalarF5E3::from(2.0), ScalarF5E3::ZERO / ScalarF5E3::ZERO, ];
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
for value in &values {
let result = value.is_normal();
std::hint::black_box(result);
}
}
let normal_check_time = start.elapsed();
assert!(
normal_check_time.as_nanos() / ((PERFORMANCE_ITERATIONS * values.len()) as u128) < 100,
"is_normal too slow: {} ns per operation",
normal_check_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128 * values.len() as u128)
);
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
for value in &values {
let result = value.is_zero();
std::hint::black_box(result);
}
}
let zero_check_time = start.elapsed();
assert!(
zero_check_time.as_nanos() / ((PERFORMANCE_ITERATIONS * values.len()) as u128) < 100,
"is_zero too slow: {} ns per operation",
zero_check_time.as_nanos() / (PERFORMANCE_ITERATIONS as u128 * values.len() as u128)
);
}
#[test]
fn test_precision_scaling_performance() {
let value_f32 = 42.0f32;
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let a = ScalarF3E3::from(value_f32);
let b = ScalarF3E3::from(value_f32 * 2.0);
let result = a + b * a / b;
std::hint::black_box(result);
}
let low_precision_time = start.elapsed();
let start = Instant::now();
for _ in 0..PERFORMANCE_ITERATIONS {
let a = ScalarF7E7::from(value_f32);
let b = ScalarF7E7::from(value_f32 * 2.0);
let result = a + b * a / b;
std::hint::black_box(result);
}
let high_precision_time = start.elapsed();
let slowdown_factor =
high_precision_time.as_nanos() as f64 / low_precision_time.as_nanos() as f64;
assert!(
slowdown_factor < 100.0,
"High precision is {}x slower than low precision (should be < 100x)",
slowdown_factor
);
}
#[test]
fn test_bulk_operation_performance() {
let size = 1000;
let values1: Vec<ScalarF5E3> = (0..size).map(|i| ScalarF5E3::from(i as f32)).collect();
let values2: Vec<ScalarF5E3> = (0..size)
.map(|i| ScalarF5E3::from((i + 1) as f32))
.collect();
let start = Instant::now();
let mut results = Vec::with_capacity(size);
for i in 0..size {
results.push(values1[i] + values2[i]);
}
let bulk_add_time = start.elapsed();
std::hint::black_box(results);
assert!(
bulk_add_time.as_nanos() / (size as u128) < MAX_OPERATION_NANOS * 2,
"Bulk addition too slow: {} ns per operation",
bulk_add_time.as_nanos() / size as u128
);
let start = Instant::now();
let mut results = Vec::with_capacity(size);
for i in 0..size {
results.push(values1[i] * values2[i]);
}
let bulk_mult_time = start.elapsed();
std::hint::black_box(results);
assert!(
bulk_mult_time.as_nanos() / (size as u128) < MAX_OPERATION_NANOS * 2,
"Bulk multiplication too slow: {} ns per operation",
bulk_mult_time.as_nanos() / size as u128
);
}
#[test]
fn test_memory_allocation_performance() {
let iterations = 1000;
let start = Instant::now();
for _ in 0..iterations {
let mut sum = ScalarF5E3::ZERO;
for i in 0..100 {
let val = ScalarF5E3::from(i as f32);
sum = sum + val;
}
std::hint::black_box(sum);
}
let allocation_time = start.elapsed();
assert!(
allocation_time.as_millis() < 100,
"Memory allocation pattern too slow: {} ms for {} iterations",
allocation_time.as_millis(),
iterations
);
}
#[test]
fn test_comparison_with_native_floats() {
let iterations = PERFORMANCE_ITERATIONS;
let values: Vec<f32> = (0..1000).map(|i| i as f32 * 0.1).collect();
let start = Instant::now();
for _ in 0..iterations {
let result = values[42] + values[43];
std::hint::black_box(result);
}
let native_add_time = start.elapsed();
let spirix_values: Vec<ScalarF5E3> = values.iter().map(|&f| ScalarF5E3::from(f)).collect();
let start = Instant::now();
for _ in 0..iterations {
let result = spirix_values[42] + spirix_values[43];
std::hint::black_box(result);
}
let spirix_add_time = start.elapsed();
let slowdown = spirix_add_time.as_nanos() as f64 / native_add_time.as_nanos() as f64;
assert!(
slowdown < 50.0,
"Spirix addition is {}x slower than native f32 (should be < 50x)",
slowdown
);
println!(
"Performance comparison - Spirix is {:.1}x slower than native f32",
slowdown
);
}