1use ocas_domain::DoubleF64;
4use pyo3::exceptions::PyValueError;
5use pyo3::prelude::*;
6
7#[pyclass(name = "DoubleF64", skip_from_py_object)]
20#[derive(Debug, Clone, Copy)]
21pub struct PyDoubleF64 {
22 pub(crate) inner: DoubleF64,
23}
24
25#[pymethods]
26impl PyDoubleF64 {
27 #[new]
34 #[pyo3(signature = (hi, lo = 0.0))]
35 fn new(hi: f64, lo: f64) -> Self {
36 Self {
37 inner: DoubleF64::new(hi, lo),
38 }
39 }
40
41 #[allow(clippy::wrong_self_convention)]
43 fn to_f64(&self) -> f64 {
44 self.inner.to_f64()
45 }
46
47 fn components(&self) -> (f64, f64) {
49 (self.inner.hi, self.inner.lo)
50 }
51
52 fn __repr__(&self) -> String {
53 format!("DoubleF64({}, {})", self.inner.hi, self.inner.lo)
54 }
55
56 fn __str__(&self) -> String {
57 format!("{}", self.inner)
58 }
59
60 fn __add__(&self, other: &Self) -> Self {
61 Self {
62 inner: self.inner + other.inner,
63 }
64 }
65
66 fn __sub__(&self, other: &Self) -> Self {
67 Self {
68 inner: self.inner - other.inner,
69 }
70 }
71
72 fn __mul__(&self, other: &Self) -> Self {
73 Self {
74 inner: self.inner * other.inner,
75 }
76 }
77
78 fn __truediv__(&self, other: &Self) -> PyResult<Self> {
79 if other.inner.hi == 0.0 && other.inner.lo == 0.0 {
80 Err(PyValueError::new_err("division by zero"))
81 } else {
82 Ok(Self {
83 inner: self.inner / other.inner,
84 })
85 }
86 }
87
88 fn __neg__(&self) -> Self {
89 Self { inner: -self.inner }
90 }
91
92 fn __abs__(&self) -> Self {
93 Self {
94 inner: self.inner.dabs(),
95 }
96 }
97
98 fn __pow__(&self, exp: i64, _mod: Option<i64>) -> Self {
99 Self {
100 inner: self.inner.powi(exp),
101 }
102 }
103
104 fn __richcmp__(&self, other: &Self, op: pyo3::basic::CompareOp) -> bool {
105 match op {
106 pyo3::basic::CompareOp::Lt => self.inner < other.inner,
107 pyo3::basic::CompareOp::Le => self.inner <= other.inner,
108 pyo3::basic::CompareOp::Eq => self.inner == other.inner,
109 pyo3::basic::CompareOp::Ne => self.inner != other.inner,
110 pyo3::basic::CompareOp::Gt => self.inner > other.inner,
111 pyo3::basic::CompareOp::Ge => self.inner >= other.inner,
112 }
113 }
114
115 fn __hash__(&self) -> u64 {
116 use std::hash::{Hash, Hasher};
117 let mut hasher = std::collections::hash_map::DefaultHasher::new();
118 self.inner.hi.to_bits().hash(&mut hasher);
119 self.inner.lo.to_bits().hash(&mut hasher);
120 hasher.finish()
121 }
122
123 fn sin(&self) -> Self {
127 Self {
128 inner: self.inner.sin(),
129 }
130 }
131
132 fn cos(&self) -> Self {
134 Self {
135 inner: self.inner.cos(),
136 }
137 }
138
139 fn tan(&self) -> Self {
141 Self {
142 inner: self.inner.tan(),
143 }
144 }
145
146 fn exp(&self) -> Self {
148 Self {
149 inner: self.inner.exp(),
150 }
151 }
152
153 fn ln(&self) -> PyResult<Self> {
155 if self.inner.hi <= 0.0 {
156 Err(PyValueError::new_err("log of non-positive number"))
157 } else {
158 Ok(Self {
159 inner: self.inner.ln(),
160 })
161 }
162 }
163
164 fn sqrt(&self) -> PyResult<Self> {
166 if self.inner.hi < 0.0 {
167 Err(PyValueError::new_err("sqrt of negative number"))
168 } else {
169 Ok(Self {
170 inner: self.inner.sqrt(),
171 })
172 }
173 }
174}