1use std::{
2 cmp,
3 f64::consts::{PI, TAU},
4 fmt,
5 hash::Hash,
6 ops,
7};
8
9use decorum::R64;
10
11#[derive(Clone, Copy, Default)]
18#[repr(C)]
19pub struct Scalar(f64);
20
21impl Scalar {
22 pub const ZERO: Self = Self(0.);
24
25 pub const ONE: Self = Self(1.);
27
28 pub const TWO: Self = Self(2.);
30
31 pub const MAX: Self = Self(f64::MAX);
33
34 pub const PI: Self = Self(PI);
36
37 pub const TAU: Self = Self(TAU);
39
40 pub fn from_f64(scalar: f64) -> Self {
46 if scalar.is_nan() {
47 panic!("Invalid scalar value: {scalar}");
48 } else {
49 Self(scalar)
50 }
51 }
52
53 pub fn from_u64(scalar: u64) -> Self {
55 Self::from_f64(scalar as f64)
56 }
57
58 pub fn into_f32(self) -> f32 {
60 self.0 as f32
61 }
62
63 pub fn into_f64(self) -> f64 {
65 self.0
66 }
67
68 pub fn into_u64(self) -> u64 {
70 self.0 as u64
71 }
72
73 pub fn is_negative(self) -> bool {
75 self < Self::ZERO
76 }
77
78 pub fn is_positive(self) -> bool {
80 self > Self::ZERO
81 }
82
83 pub fn is_zero(self) -> bool {
85 self == Self::ZERO
86 }
87
88 pub fn sign(self) -> Sign {
93 if self.is_negative() {
94 return Sign::Negative;
95 }
96 if self.is_positive() {
97 return Sign::Positive;
98 }
99 if self.is_zero() {
100 return Sign::Zero;
101 }
102
103 unreachable!("Sign is neither negative, nor positive, nor zero.")
104 }
105
106 pub fn abs(self) -> Self {
108 self.0.abs().into()
109 }
110
111 pub fn max(self, other: impl Into<Self>) -> Self {
113 self.0.max(other.into().0).into()
114 }
115
116 pub fn floor(self) -> Self {
118 self.0.floor().into()
119 }
120
121 pub fn ceil(self) -> Self {
123 self.0.ceil().into()
124 }
125
126 pub fn round(self) -> Self {
128 self.0.round().into()
129 }
130
131 pub fn cos(self) -> Self {
133 self.0.cos().into()
134 }
135
136 pub fn sin_cos(self) -> (Self, Self) {
138 let (sin, cos) = self.0.sin_cos();
139 (sin.into(), cos.into())
140 }
141
142 pub fn acos(self) -> Self {
144 self.0.acos().into()
145 }
146
147 pub fn atan2(self, other: Self) -> Self {
149 self.0.atan2(other.0).into()
150 }
151}
152
153impl PartialEq for Scalar {
154 fn eq(&self, other: &Self) -> bool {
155 self.0 == other.0
156 }
157}
158
159impl Eq for Scalar {}
160
161impl PartialOrd for Scalar {
162 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
163 Some(self.cmp(other))
164 }
165}
166
167impl Ord for Scalar {
168 fn cmp(&self, other: &Self) -> cmp::Ordering {
169 self.0.partial_cmp(&other.0).expect("Invalid `Scalar`")
172 }
173}
174
175impl Hash for Scalar {
176 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
177 R64::from_inner(self.0).hash(state);
180 }
181}
182
183impl From<f32> for Scalar {
184 fn from(scalar: f32) -> Self {
185 Self::from_f64(scalar.into())
186 }
187}
188
189impl From<f64> for Scalar {
190 fn from(scalar: f64) -> Self {
191 Self::from_f64(scalar)
192 }
193}
194
195impl From<Scalar> for f64 {
196 fn from(scalar: Scalar) -> Self {
197 scalar.into_f64()
198 }
199}
200
201impl ops::Neg for Scalar {
202 type Output = Self;
203
204 fn neg(self) -> Self::Output {
205 self.0.neg().into()
206 }
207}
208
209impl<T: Into<Self>> ops::Add<T> for Scalar {
210 type Output = Self;
211
212 fn add(self, rhs: T) -> Self::Output {
213 self.0.add(rhs.into().0).into()
214 }
215}
216
217impl<T: Into<Self>> ops::Sub<T> for Scalar {
218 type Output = Self;
219
220 fn sub(self, rhs: T) -> Self::Output {
221 self.0.sub(rhs.into().0).into()
222 }
223}
224
225impl<T: Into<Self>> ops::Mul<T> for Scalar {
226 type Output = Self;
227
228 fn mul(self, rhs: T) -> Self::Output {
229 self.0.mul(rhs.into().0).into()
230 }
231}
232
233impl<T: Into<Self>> ops::Div<T> for Scalar {
234 type Output = Self;
235
236 fn div(self, rhs: T) -> Self::Output {
237 self.0.div(rhs.into().0).into()
238 }
239}
240
241impl<T: Into<Self>> ops::Rem<T> for Scalar {
242 type Output = Self;
243
244 fn rem(self, rhs: T) -> Self::Output {
245 self.0.rem(rhs.into().0).into()
246 }
247}
248
249impl<T: Into<Self>> ops::AddAssign<T> for Scalar {
250 fn add_assign(&mut self, rhs: T) {
251 self.0.add_assign(rhs.into().0);
252 *self = self.0.into();
253 }
254}
255
256impl<T: Into<Self>> ops::SubAssign<T> for Scalar {
257 fn sub_assign(&mut self, rhs: T) {
258 self.0.sub_assign(rhs.into().0);
259 *self = self.0.into();
260 }
261}
262
263impl<T: Into<Self>> ops::MulAssign<T> for Scalar {
264 fn mul_assign(&mut self, rhs: T) {
265 self.0.mul_assign(rhs.into().0);
266 *self = self.0.into();
267 }
268}
269
270impl<T: Into<Self>> ops::DivAssign<T> for Scalar {
271 fn div_assign(&mut self, rhs: T) {
272 self.0.div_assign(rhs.into().0);
273 *self = self.0.into();
274 }
275}
276
277impl<T: Into<Self>> ops::RemAssign<T> for Scalar {
278 fn rem_assign(&mut self, rhs: T) {
279 self.0.rem_assign(rhs.into().0);
280 *self = self.0.into();
281 }
282}
283
284impl num_traits::Zero for Scalar {
285 fn zero() -> Self {
286 Self::ZERO
287 }
288
289 fn is_zero(&self) -> bool {
290 self.0.is_zero()
291 }
292}
293
294impl num_traits::One for Scalar {
295 fn one() -> Self {
296 Self::ONE
297 }
298}
299
300impl num_traits::Num for Scalar {
301 type FromStrRadixErr = <f64 as num_traits::Num>::FromStrRadixErr;
302
303 fn from_str_radix(
304 str: &str,
305 radix: u32,
306 ) -> Result<Self, Self::FromStrRadixErr> {
307 f64::from_str_radix(str, radix).map(Self::from_f64)
308 }
309}
310
311impl num_traits::NumCast for Scalar {
312 fn from<T: num_traits::ToPrimitive>(n: T) -> Option<Self> {
313 Some(Self::from_f64(<f64 as num_traits::NumCast>::from(n)?))
314 }
315}
316
317impl num_traits::Signed for Scalar {
318 fn abs(&self) -> Self {
319 self.0.abs().into()
320 }
321
322 fn abs_sub(&self, other: &Self) -> Self {
323 <f64 as num_traits::Signed>::abs_sub(&self.0, &other.0).into()
324 }
325
326 fn signum(&self) -> Self {
327 <f64 as num_traits::Signed>::signum(&self.0).into()
328 }
329
330 fn is_positive(&self) -> bool {
331 <f64 as num_traits::Signed>::is_positive(&self.0)
332 }
333
334 fn is_negative(&self) -> bool {
335 <f64 as num_traits::Signed>::is_negative(&self.0)
336 }
337}
338
339impl num_traits::ToPrimitive for Scalar {
340 fn to_i64(&self) -> Option<i64> {
341 self.0.to_i64()
342 }
343
344 fn to_u64(&self) -> Option<u64> {
345 self.0.to_u64()
346 }
347}
348
349impl num_traits::Float for Scalar {
350 fn nan() -> Self {
351 panic!("`Scalar` can not represent NaN")
352 }
353
354 fn infinity() -> Self {
355 Self::from_f64(f64::infinity())
356 }
357
358 fn neg_infinity() -> Self {
359 Self::from_f64(f64::neg_infinity())
360 }
361
362 fn neg_zero() -> Self {
363 Self::from_f64(f64::neg_zero())
364 }
365
366 fn min_value() -> Self {
367 Self::from_f64(f64::min_value())
368 }
369
370 fn min_positive_value() -> Self {
371 Self::from_f64(f64::min_positive_value())
372 }
373
374 fn max_value() -> Self {
375 Self::from_f64(f64::max_value())
376 }
377
378 fn is_nan(self) -> bool {
379 self.0.is_nan()
380 }
381
382 fn is_infinite(self) -> bool {
383 self.0.is_infinite()
384 }
385
386 fn is_finite(self) -> bool {
387 self.0.is_finite()
388 }
389
390 fn is_normal(self) -> bool {
391 self.0.is_normal()
392 }
393
394 fn classify(self) -> std::num::FpCategory {
395 self.0.classify()
396 }
397
398 fn floor(self) -> Self {
399 Self::from_f64(self.0.floor())
400 }
401
402 fn ceil(self) -> Self {
403 Self::from_f64(self.0.ceil())
404 }
405
406 fn round(self) -> Self {
407 Self::from_f64(self.0.round())
408 }
409
410 fn trunc(self) -> Self {
411 Self::from_f64(self.0.trunc())
412 }
413
414 fn fract(self) -> Self {
415 Self::from_f64(self.0.fract())
416 }
417
418 fn abs(self) -> Self {
419 Self::from_f64(self.0.abs())
420 }
421
422 fn signum(self) -> Self {
423 Self::from_f64(self.0.signum())
424 }
425
426 fn is_sign_positive(self) -> bool {
427 self.0.is_sign_positive()
428 }
429
430 fn is_sign_negative(self) -> bool {
431 self.0.is_sign_negative()
432 }
433
434 fn mul_add(self, a: Self, b: Self) -> Self {
435 Self::from_f64(self.0.mul_add(a.0, b.0))
436 }
437
438 fn recip(self) -> Self {
439 Self::from_f64(self.0.recip())
440 }
441
442 fn powi(self, n: i32) -> Self {
443 Self::from_f64(self.0.powi(n))
444 }
445
446 fn powf(self, n: Self) -> Self {
447 Self::from_f64(self.0.powf(n.0))
448 }
449
450 fn sqrt(self) -> Self {
451 Self::from_f64(self.0.sqrt())
452 }
453
454 fn exp(self) -> Self {
455 Self::from_f64(self.0.exp())
456 }
457
458 fn exp2(self) -> Self {
459 Self::from_f64(self.0.exp2())
460 }
461
462 fn ln(self) -> Self {
463 Self::from_f64(self.0.ln())
464 }
465
466 fn log(self, base: Self) -> Self {
467 Self::from_f64(self.0.log(base.0))
468 }
469
470 fn log2(self) -> Self {
471 Self::from_f64(self.0.log2())
472 }
473
474 fn log10(self) -> Self {
475 Self::from_f64(self.0.log10())
476 }
477
478 fn max(self, other: Self) -> Self {
479 Self::from_f64(self.0.max(other.0))
480 }
481
482 fn min(self, other: Self) -> Self {
483 Self::from_f64(self.0.min(other.0))
484 }
485
486 fn abs_sub(self, other: Self) -> Self {
487 (self - other).abs()
488 }
489
490 fn cbrt(self) -> Self {
491 Self::from_f64(self.0.cbrt())
492 }
493
494 fn hypot(self, other: Self) -> Self {
495 Self::from_f64(self.0.hypot(other.0))
496 }
497
498 fn sin(self) -> Self {
499 Self::from_f64(self.0.sin())
500 }
501
502 fn cos(self) -> Self {
503 Self::from_f64(self.0.cos())
504 }
505
506 fn tan(self) -> Self {
507 Self::from_f64(self.0.tan())
508 }
509
510 fn asin(self) -> Self {
511 Self::from_f64(self.0.asin())
512 }
513
514 fn acos(self) -> Self {
515 Self::from_f64(self.0.acos())
516 }
517
518 fn atan(self) -> Self {
519 Self::from_f64(self.0.atan())
520 }
521
522 fn atan2(self, other: Self) -> Self {
523 Self::from_f64(self.0.atan2(other.0))
524 }
525
526 fn sin_cos(self) -> (Self, Self) {
527 let (sin, cos) = self.0.sin_cos();
528 (Self::from_f64(sin), Self::from_f64(cos))
529 }
530
531 fn exp_m1(self) -> Self {
532 Self::from_f64(self.0.exp_m1())
533 }
534
535 fn ln_1p(self) -> Self {
536 Self::from_f64(self.0.ln_1p())
537 }
538
539 fn sinh(self) -> Self {
540 Self::from_f64(self.0.sinh())
541 }
542
543 fn cosh(self) -> Self {
544 Self::from_f64(self.0.cosh())
545 }
546
547 fn tanh(self) -> Self {
548 Self::from_f64(self.0.tanh())
549 }
550
551 fn asinh(self) -> Self {
552 Self::from_f64(self.0.asinh())
553 }
554
555 fn acosh(self) -> Self {
556 Self::from_f64(self.0.acosh())
557 }
558
559 fn atanh(self) -> Self {
560 Self::from_f64(self.0.atanh())
561 }
562
563 fn integer_decode(self) -> (u64, i16, i8) {
564 self.0.integer_decode()
565 }
566}
567
568impl fmt::Debug for Scalar {
569 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
570 self.0.fmt(f)
571 }
572}
573
574impl fmt::Display for Scalar {
575 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
576 self.0.fmt(f)
577 }
578}
579
580impl approx::AbsDiffEq for Scalar {
581 type Epsilon = Self;
582
583 fn default_epsilon() -> Self::Epsilon {
584 f64::default_epsilon().into()
585 }
586
587 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
588 self.0.abs_diff_eq(&other.0, epsilon.0)
589 }
590}
591
592#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
596pub enum Sign {
597 Negative,
599
600 Positive,
602
603 Zero,
605}
606
607impl Sign {
608 pub fn to_scalar(self) -> Scalar {
610 match self {
611 Self::Negative => -Scalar::ONE,
612 Self::Positive => Scalar::ONE,
613 Self::Zero => Scalar::ZERO,
614 }
615 }
616}