#![forbid(unsafe_code)]
use core::str::FromStr;
pub use oxinum_core::{OxiNumError, OxiNumResult};
pub use oxinum_float::DBig;
#[derive(Clone)]
pub struct CBig {
pub(crate) re: DBig,
pub(crate) im: DBig,
}
impl CBig {
pub fn new(re: DBig, im: DBig) -> Self {
Self::from_parts(re, im)
}
pub fn from_parts(re: DBig, im: DBig) -> Self {
Self { re, im }
}
pub fn from_real(re: DBig) -> Self {
Self {
re,
im: DBig::from(0u32),
}
}
pub fn from_imag(im: DBig) -> Self {
Self {
re: DBig::from(0u32),
im,
}
}
pub fn zero() -> Self {
Self {
re: DBig::from(0u32),
im: DBig::from(0u32),
}
}
pub fn one() -> Self {
Self {
re: DBig::from(1u32),
im: DBig::from(0u32),
}
}
pub fn i() -> Self {
Self {
re: DBig::from(0u32),
im: DBig::from(1u32),
}
}
pub fn from_f64(re: f64, im: f64) -> OxiNumResult<Self> {
Ok(Self {
re: f64_to_dbig(re)?,
im: f64_to_dbig(im)?,
})
}
pub fn re(&self) -> &DBig {
&self.re
}
pub fn im(&self) -> &DBig {
&self.im
}
pub fn real(&self) -> DBig {
self.re.clone()
}
pub fn imag(&self) -> DBig {
self.im.clone()
}
pub fn into_parts(self) -> (DBig, DBig) {
(self.re, self.im)
}
pub fn conj(&self) -> Self {
Self {
re: self.re.clone(),
im: -self.im.clone(),
}
}
pub fn norm_sqr(&self) -> DBig {
(&self.re * &self.re) + (&self.im * &self.im)
}
pub fn is_zero(&self) -> bool {
let zero = DBig::from(0u32);
self.re == zero && self.im == zero
}
pub fn is_real(&self) -> bool {
self.im == DBig::from(0u32)
}
pub fn is_imaginary(&self) -> bool {
self.re == DBig::from(0u32)
}
}
fn f64_to_dbig(v: f64) -> OxiNumResult<DBig> {
if v.is_nan() {
return Err(OxiNumError::Parse("cannot encode NaN as DBig".into()));
}
if v.is_infinite() {
return Err(OxiNumError::Parse("cannot encode infinity as DBig".into()));
}
let s = format!("{v:.17e}");
DBig::from_str(&s).map_err(|e| OxiNumError::Parse(format!("invalid f64→DBig: {e:?}").into()))
}
mod convert;
mod fmt;
mod ops;
mod transcendental;
mod trig;
#[cfg(feature = "num-traits")]
mod num_traits_impl;
#[cfg(feature = "serde")]
mod serde_impl;
pub mod native;
pub type Complex = CBig;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_one_i_constructors() {
let z = CBig::zero();
assert!(z.is_zero());
assert_eq!(z.re().to_string(), "0");
assert_eq!(z.im().to_string(), "0");
let one = CBig::one();
assert!(one.is_real());
assert_eq!(one.re().to_string(), "1");
assert_eq!(one.im().to_string(), "0");
let imag = CBig::i();
assert!(imag.is_imaginary());
assert_eq!(imag.re().to_string(), "0");
assert_eq!(imag.im().to_string(), "1");
}
#[test]
fn from_parts_round_trip() {
let z = CBig::from_f64(2.5, -7.0).expect("finite parts");
let (re, im) = z.clone().into_parts();
assert_eq!(re.to_string(), "2.5");
assert_eq!(im.to_string(), "-7");
assert_eq!(z.real().to_string(), "2.5");
assert_eq!(z.imag().to_string(), "-7");
}
#[test]
fn conj_negates_imag_and_norm_sqr() {
let z = CBig::from_f64(3.0, 4.0).expect("finite parts");
let c = z.conj();
assert_eq!(c.re().to_string(), "3");
assert_eq!(c.im().to_string(), "-4");
assert_eq!(z.norm_sqr().to_string(), "25");
}
#[test]
fn from_f64_rejects_non_finite() {
assert!(CBig::from_f64(f64::NAN, 0.0).is_err());
assert!(CBig::from_f64(0.0, f64::INFINITY).is_err());
assert!(CBig::from_f64(f64::NEG_INFINITY, 1.0).is_err());
}
}