#![forbid(unsafe_code)]
use la_stack::prelude::*;
fn main() -> Result<(), LaError> {
let perturbation = f64::from_bits(0x3CD0_0000_0000_0000); let a = Matrix::<3>::try_from_rows([
[1.0 + perturbation, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0],
])?;
let b = Vector::<3>::try_new([1.0, 2.0, 3.0])?;
let lu_x = a.lu(Tolerance::try_new(0.0)?)?.solve(b)?.into_array();
let exact_x = a.solve_exact(b)?;
assert_eq!(
exact_x.as_array(),
&[
BigRational::from_integer(0.into()),
BigRational::from_integer(0.into()),
BigRational::new(1.into(), 3.into()),
],
);
println!("Near-singular 3×3 system (perturbation = 2^-50 ≈ {perturbation:.2e}):");
for row in a.as_rows() {
print!(" [");
for (col, value) in row.iter().enumerate() {
if col > 0 {
print!(", ");
}
print!("{value:22.18}");
}
println!("]");
}
println!(
"b = [{}, {}, {}]",
b.as_array()[0],
b.as_array()[1],
b.as_array()[2]
);
println!();
println!(
"f64 LU solve: x = [{:+.6e}, {:+.6e}, {:+.6e}]",
lu_x[0], lu_x[1], lu_x[2]
);
println!(
"solve_exact(): x = [{}, {}, {}]",
exact_x.as_array()[0],
exact_x.as_array()[1],
exact_x.as_array()[2]
);
let strict = exact_x.try_to_f64();
assert_eq!(
strict,
Err(LaError::unrepresentable(
Some(2),
UnrepresentableReason::RequiresRounding,
)),
);
match strict {
Ok(x) => {
let x = x.into_array();
println!(
"exact try_to_f64(): x = [{:+.6e}, {:+.6e}, {:+.6e}]",
x[0], x[1], x[2]
);
}
Err(err) if err.requires_rounding() => {
println!("exact try_to_f64(): {err}");
let x = exact_x.to_rounded_f64()?.into_array();
assert_eq!(x.map(f64::to_bits), [0, 0, 0x3fd5_5555_5555_5555]);
println!(
"exact to_rounded_f64(): x = [{:+.6e}, {:+.6e}, {:+.6e}]",
x[0], x[1], x[2]
);
}
Err(err) => return Err(err),
}
Ok(())
}