1use std::cmp::Ordering;
2use std::fmt::{self, Debug, Formatter};
3use std::hash::{Hash, Hasher};
4use std::iter::Sum;
5use std::ops::{
6 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
7};
8
9use crate::Numeric;
10
11#[derive(Default, Copy, Clone)]
15pub struct Scalar(f64);
16
17impl Scalar {
18 pub const ZERO: Self = Self(0.0);
20
21 pub const ONE: Self = Self(1.0);
23
24 pub const INFINITY: Self = Self(f64::INFINITY);
26
27 pub const fn new(x: f64) -> Self {
31 Self(if is_nan(x) { 0.0 } else { x })
32 }
33
34 pub const fn get(self) -> f64 {
36 self.0
37 }
38}
39
40#[allow(clippy::unusual_byte_groupings)]
44const fn is_nan(x: f64) -> bool {
45 let x_bits = unsafe { std::mem::transmute::<f64, u64>(x) };
48 (x_bits << 1 >> (64 - 12 + 1)) == 0b0_111_1111_1111 && (x_bits << 12) != 0
49}
50
51impl Numeric for Scalar {
52 fn zero() -> Self {
53 Self(0.0)
54 }
55
56 fn is_finite(self) -> bool {
57 self.0.is_finite()
58 }
59}
60
61impl Debug for Scalar {
62 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
63 self.0.fmt(f)
64 }
65}
66
67impl Eq for Scalar {}
68
69impl PartialEq for Scalar {
70 fn eq(&self, other: &Self) -> bool {
71 assert!(!self.0.is_nan() && !other.0.is_nan(), "float is NaN");
72 self.0 == other.0
73 }
74}
75
76impl PartialEq<f64> for Scalar {
77 fn eq(&self, other: &f64) -> bool {
78 self == &Self(*other)
79 }
80}
81
82impl Ord for Scalar {
83 fn cmp(&self, other: &Self) -> Ordering {
84 self.0.partial_cmp(&other.0).expect("float is NaN")
85 }
86}
87
88impl PartialOrd for Scalar {
89 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
90 Some(self.cmp(other))
91 }
92}
93
94impl Hash for Scalar {
95 fn hash<H: Hasher>(&self, state: &mut H) {
96 debug_assert!(!self.0.is_nan(), "float is NaN");
97 self.0.to_bits().hash(state);
98 }
99}
100
101impl From<f64> for Scalar {
102 fn from(float: f64) -> Self {
103 Self::new(float)
104 }
105}
106
107impl From<Scalar> for f64 {
108 fn from(scalar: Scalar) -> Self {
109 scalar.0
110 }
111}
112
113impl Neg for Scalar {
114 type Output = Self;
115
116 fn neg(self) -> Self::Output {
117 Self::new(-self.0)
118 }
119}
120
121impl<T: Into<Self>> Add<T> for Scalar {
122 type Output = Self;
123
124 fn add(self, rhs: T) -> Self::Output {
125 Self::new(self.0 + rhs.into().0)
126 }
127}
128
129impl<T: Into<Self>> AddAssign<T> for Scalar {
130 fn add_assign(&mut self, rhs: T) {
131 *self = *self + rhs.into();
132 }
133}
134
135impl<T: Into<Self>> Sub<T> for Scalar {
136 type Output = Self;
137
138 fn sub(self, rhs: T) -> Self::Output {
139 Self::new(self.0 - rhs.into().0)
140 }
141}
142
143impl<T: Into<Self>> SubAssign<T> for Scalar {
144 fn sub_assign(&mut self, rhs: T) {
145 *self = *self - rhs.into();
146 }
147}
148
149impl<T: Into<Self>> Mul<T> for Scalar {
150 type Output = Self;
151
152 fn mul(self, rhs: T) -> Self::Output {
153 Self::new(self.0 * rhs.into().0)
154 }
155}
156
157impl<T: Into<Self>> MulAssign<T> for Scalar {
158 fn mul_assign(&mut self, rhs: T) {
159 *self = *self * rhs.into();
160 }
161}
162
163impl<T: Into<Self>> Div<T> for Scalar {
164 type Output = Self;
165
166 fn div(self, rhs: T) -> Self::Output {
167 Self::new(self.0 / rhs.into().0)
168 }
169}
170
171impl<T: Into<Self>> DivAssign<T> for Scalar {
172 fn div_assign(&mut self, rhs: T) {
173 *self = *self / rhs.into();
174 }
175}
176
177impl<T: Into<Self>> Rem<T> for Scalar {
178 type Output = Self;
179
180 fn rem(self, rhs: T) -> Self::Output {
181 Self::new(self.0 % rhs.into().0)
182 }
183}
184
185impl<T: Into<Self>> RemAssign<T> for Scalar {
186 fn rem_assign(&mut self, rhs: T) {
187 *self = *self % rhs.into();
188 }
189}
190
191impl Sum for Scalar {
192 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
193 Self::new(iter.map(|s| s.0).sum())
194 }
195}
196
197impl<'a> Sum<&'a Self> for Scalar {
198 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
199 Self::new(iter.map(|s| s.0).sum())
200 }
201}