use ocas_domain::DoubleF64;
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
#[pyclass(name = "DoubleF64", skip_from_py_object)]
#[derive(Debug, Clone, Copy)]
pub struct PyDoubleF64 {
pub(crate) inner: DoubleF64,
}
#[pymethods]
impl PyDoubleF64 {
#[new]
#[pyo3(signature = (hi, lo = 0.0))]
fn new(hi: f64, lo: f64) -> Self {
Self {
inner: DoubleF64::new(hi, lo),
}
}
#[allow(clippy::wrong_self_convention)]
fn to_f64(&self) -> f64 {
self.inner.to_f64()
}
fn components(&self) -> (f64, f64) {
(self.inner.hi, self.inner.lo)
}
fn __repr__(&self) -> String {
format!("DoubleF64({}, {})", self.inner.hi, self.inner.lo)
}
fn __str__(&self) -> String {
format!("{}", self.inner)
}
fn __add__(&self, other: &Self) -> Self {
Self {
inner: self.inner + other.inner,
}
}
fn __sub__(&self, other: &Self) -> Self {
Self {
inner: self.inner - other.inner,
}
}
fn __mul__(&self, other: &Self) -> Self {
Self {
inner: self.inner * other.inner,
}
}
fn __truediv__(&self, other: &Self) -> PyResult<Self> {
if other.inner.hi == 0.0 && other.inner.lo == 0.0 {
Err(PyValueError::new_err("division by zero"))
} else {
Ok(Self {
inner: self.inner / other.inner,
})
}
}
fn __neg__(&self) -> Self {
Self { inner: -self.inner }
}
fn __abs__(&self) -> Self {
Self {
inner: self.inner.dabs(),
}
}
fn __pow__(&self, exp: i64, _mod: Option<i64>) -> Self {
Self {
inner: self.inner.powi(exp),
}
}
fn __richcmp__(&self, other: &Self, op: pyo3::basic::CompareOp) -> bool {
match op {
pyo3::basic::CompareOp::Lt => self.inner < other.inner,
pyo3::basic::CompareOp::Le => self.inner <= other.inner,
pyo3::basic::CompareOp::Eq => self.inner == other.inner,
pyo3::basic::CompareOp::Ne => self.inner != other.inner,
pyo3::basic::CompareOp::Gt => self.inner > other.inner,
pyo3::basic::CompareOp::Ge => self.inner >= other.inner,
}
}
fn __hash__(&self) -> u64 {
use std::hash::{Hash, Hasher};
let mut hasher = std::collections::hash_map::DefaultHasher::new();
self.inner.hi.to_bits().hash(&mut hasher);
self.inner.lo.to_bits().hash(&mut hasher);
hasher.finish()
}
fn sin(&self) -> Self {
Self {
inner: self.inner.sin(),
}
}
fn cos(&self) -> Self {
Self {
inner: self.inner.cos(),
}
}
fn tan(&self) -> Self {
Self {
inner: self.inner.tan(),
}
}
fn exp(&self) -> Self {
Self {
inner: self.inner.exp(),
}
}
fn ln(&self) -> PyResult<Self> {
if self.inner.hi <= 0.0 {
Err(PyValueError::new_err("log of non-positive number"))
} else {
Ok(Self {
inner: self.inner.ln(),
})
}
}
fn sqrt(&self) -> PyResult<Self> {
if self.inner.hi < 0.0 {
Err(PyValueError::new_err("sqrt of negative number"))
} else {
Ok(Self {
inner: self.inner.sqrt(),
})
}
}
}