use axiolid_guarantees::Sign;
use crate::arith::{sign_product, Arith};
#[derive(Debug, Clone, PartialEq)]
pub struct Root2<T> {
pub a: T,
pub b: T,
pub c: T,
pub d: T,
}
impl<T: Arith> Root2<T> {
#[must_use]
pub fn sign(&self) -> Option<Sign> {
let denominator = self.d.sign()?;
if denominator == Sign::Zero {
return None;
}
Some(sign_product(
sign_root(&self.a, &self.b, &self.c)?,
denominator,
))
}
#[must_use]
pub fn cmp_sign(&self, other: &Self) -> Option<Sign> {
let d1 = self.d.sign()?;
let d2 = other.d.sign()?;
if d1 == Sign::Zero || d2 == Sign::Zero {
return None;
}
let p = self.a.mul(&other.d).sub(&other.a.mul(&self.d));
let q = self.b.mul(&other.d);
let r = other.b.mul(&self.d).neg();
let inner = sign_two_roots(&p, &q, &self.c, &r, &other.c)?;
Some(sign_product(sign_product(inner, d1), d2))
}
}
#[must_use]
pub fn sign_root<T: Arith>(a: &T, b: &T, c: &T) -> Option<Sign> {
let radicand = c.sign()?;
if radicand == Sign::Negative {
return None;
}
let sa = a.sign()?;
let sb = if radicand == Sign::Zero {
Sign::Zero
} else {
b.sign()?
};
if sb == Sign::Zero {
return Some(sa);
}
if sa == Sign::Zero || sa == sb {
return Some(sb);
}
let dominance = a.square().sub(&b.square().mul(c)).sign()?;
Some(sign_product(sa, dominance))
}
#[must_use]
pub fn sign_two_roots<T: Arith>(p: &T, q: &T, c: &T, r: &T, e: &T) -> Option<Sign> {
let su = sign_root(p, q, c)?;
let radicand = e.sign()?;
if radicand == Sign::Negative {
return None;
}
let sv = if radicand == Sign::Zero {
Sign::Zero
} else {
r.sign()?
};
if sv == Sign::Zero {
return Some(su);
}
if su == Sign::Zero || su == sv {
return Some(sv);
}
let rational = p.square().add(&q.square().mul(c)).sub(&r.square().mul(e));
let two = T::from_f64(2.0);
let irrational = two.mul(p).mul(q);
let dominance = sign_root(&rational, &irrational, c)?;
Some(sign_product(su, dominance))
}