use core::str::FromStr;
use oxinum_complex::{CBig, DBig};
use oxinum_float::compute_pi;
const TOL: f64 = 1e-12;
const PREC: usize = 40;
const PI_PREC: usize = 50;
fn d(s: &str) -> DBig {
DBig::from_str(s).expect("valid decimal literal")
}
fn assert_close(parts: (f64, f64), re_ref: f64, im_ref: f64, label: &str) {
let (re, im) = parts;
assert!(
(re - re_ref).abs() < TOL,
"{label}: re = {re}, expected {re_ref}"
);
assert!(
(im - im_ref).abs() < TOL,
"{label}: im = {im}, expected {im_ref}"
);
}
#[test]
fn exp_i_pi_is_minus_one() {
let z = CBig::from_parts(d("0"), compute_pi(PI_PREC));
let r = z.exp(PREC).expect("exp");
assert_close(r.to_f64_parts(), -1.0, 0.0, "exp(iπ)");
}
#[test]
fn exp_zero_is_one() {
let r = CBig::zero().exp(PREC).expect("exp");
assert_close(r.to_f64_parts(), 1.0, 0.0, "exp(0)");
}
#[test]
fn ln_minus_one_is_i_pi() {
let z = CBig::from_real(d("-1"));
let r = z.ln(PREC).expect("ln");
assert_close(r.to_f64_parts(), 0.0, std::f64::consts::PI, "ln(−1)");
}
#[test]
fn ln_i_is_half_i_pi() {
let r = CBig::i().ln(PREC).expect("ln");
assert_close(r.to_f64_parts(), 0.0, std::f64::consts::FRAC_PI_2, "ln(i)");
}
#[test]
fn ln_zero_is_err() {
assert!(CBig::zero().ln(PREC).is_err(), "ln(0) should error");
}
#[test]
fn sqrt_minus_one_is_i() {
let z = CBig::from_real(d("-1"));
let r = z.sqrt(PREC).expect("sqrt");
assert_close(r.to_f64_parts(), 0.0, 1.0, "sqrt(−1)");
}
#[test]
fn sqrt_two_i_is_one_plus_i() {
let z = CBig::from_parts(d("0"), d("2"));
let r = z.sqrt(PREC).expect("sqrt");
assert_close(r.to_f64_parts(), 1.0, 1.0, "sqrt(2i)");
}
#[test]
fn sqrt_zero_is_zero() {
let r = CBig::zero().sqrt(PREC).expect("sqrt");
assert!(r.is_zero(), "sqrt(0) should be exactly zero");
}
#[test]
fn one_plus_i_squared_is_two_i_exact() {
let z = CBig::from_f64(1.0, 1.0).expect("finite parts");
let sq = &z * &z;
assert_eq!(sq.re().to_string(), "0", "re of (1+i)²");
assert_eq!(sq.im().to_string(), "2", "im of (1+i)²");
}
#[test]
fn abs_three_four_is_five() {
let z = CBig::from_f64(3.0, 4.0).expect("finite parts");
let m = z.abs(PREC).expect("abs");
assert!(m.to_string().starts_with('5'), "|3+4i| = {m}");
assert!((m.to_f64().value() - 5.0).abs() < TOL, "|3+4i| f64 = {m}");
}
#[test]
fn arg_of_i_is_half_pi() {
let a = CBig::i().arg(PREC).expect("arg");
assert!(
(a.to_f64().value() - std::f64::consts::FRAC_PI_2).abs() < TOL,
"arg(i) = {a}"
);
}
#[test]
fn arg_of_minus_one_is_pi() {
let a = CBig::from_real(d("-1")).arg(PREC).expect("arg");
assert!(
(a.to_f64().value() - std::f64::consts::PI).abs() < TOL,
"arg(−1) = {a}"
);
}
#[test]
fn arg_of_one_plus_i_is_quarter_pi() {
let a = CBig::from_f64(1.0, 1.0)
.expect("finite parts")
.arg(PREC)
.expect("arg");
assert!(
(a.to_f64().value() - std::f64::consts::FRAC_PI_4).abs() < TOL,
"arg(1+i) = {a}"
);
}
fn real_exp(n: f64) -> CBig {
CBig::from_f64(n, 0.0).expect("finite exponent")
}
#[test]
fn pow_i_squared_is_minus_one() {
let r = CBig::i().pow(&real_exp(2.0), PREC).expect("pow");
assert_close(r.to_f64_parts(), -1.0, 0.0, "i²");
}
#[test]
fn pow_off_axis_to_one_is_identity() {
let z = CBig::from_f64(2.0, -3.0).expect("finite parts");
let r = z.pow(&CBig::one(), PREC).expect("pow");
assert_close(r.to_f64_parts(), 2.0, -3.0, "(2−3i)^1");
}
#[test]
fn pow_one_plus_i_squared_is_two_i() {
let z = CBig::from_f64(1.0, 1.0).expect("finite parts");
let r = z.pow(&real_exp(2.0), PREC).expect("pow");
assert_close(r.to_f64_parts(), 0.0, 2.0, "(1+i)^2");
}