1use crate::{Derivative, DualNum, DualNumFloat, DualStruct};
2use approx::{AbsDiffEq, RelativeEq, UlpsEq};
3use nalgebra::allocator::Allocator;
4use nalgebra::*;
5use num_traits::{Float, FloatConst, FromPrimitive, Inv, Num, One, Signed, Zero};
6use std::fmt;
7use std::iter::{Product, Sum};
8use std::marker::PhantomData;
9use std::ops::{
10 Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,
11};
12
13#[derive(Clone, Debug)]
15pub struct Dual2Vec<T: DualNum<F>, F, D: Dim>
16where
17 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
18{
19 pub re: T,
21 pub v1: Derivative<T, F, U1, D>,
23 pub v2: Derivative<T, F, D, D>,
25 f: PhantomData<F>,
26}
27
28impl<T: DualNum<F> + Copy, F: Copy, const N: usize> Copy for Dual2Vec<T, F, Const<N>> {}
29
30#[cfg(feature = "ndarray")]
31impl<T: DualNum<F>, F: DualNumFloat, D: Dim> ndarray::ScalarOperand for Dual2Vec<T, F, D> where
32 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>
33{
34}
35
36pub type Dual2SVec<T, F, const N: usize> = Dual2Vec<T, F, Const<N>>;
37pub type Dual2DVec<T, F> = Dual2Vec<T, F, Dyn>;
38pub type Dual2Vec32<D> = Dual2Vec<f32, f32, D>;
39pub type Dual2Vec64<D> = Dual2Vec<f64, f64, D>;
40pub type Dual2SVec32<const N: usize> = Dual2Vec<f32, f32, Const<N>>;
41pub type Dual2SVec64<const N: usize> = Dual2Vec<f64, f64, Const<N>>;
42pub type Dual2DVec32 = Dual2Vec<f32, f32, Dyn>;
43pub type Dual2DVec64 = Dual2Vec<f64, f64, Dyn>;
44
45impl<T: DualNum<F>, F, D: Dim> Dual2Vec<T, F, D>
46where
47 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
48{
49 #[inline]
51 pub fn new(re: T, v1: Derivative<T, F, U1, D>, v2: Derivative<T, F, D, D>) -> Self {
52 Self {
53 re,
54 v1,
55 v2,
56 f: PhantomData,
57 }
58 }
59}
60
61impl<T: DualNum<F>, F, const N: usize> Dual2SVec<T, F, N> {
62 #[inline]
78 pub fn derivative(mut self, index: usize) -> Self {
79 self.v1 = Derivative::derivative_generic(U1, Const::<N>, index);
80 self
81 }
82}
83
84impl<T: DualNum<F>, F> Dual2DVec<T, F> {
85 #[inline]
101 pub fn derivative(mut self, variables: usize, index: usize) -> Self {
102 self.v1 = Derivative::derivative_generic(U1, Dyn(variables), index);
103 self
104 }
105}
106
107impl<T: DualNum<F>, F, D: Dim> Dual2Vec<T, F, D>
108where
109 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
110{
111 #[inline]
113 pub fn from_re(re: T) -> Self {
114 Self::new(re, Derivative::none(), Derivative::none())
115 }
116}
117
118impl<T: DualNum<F>, F: Float, D: Dim> Dual2Vec<T, F, D>
120where
121 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
122{
123 #[inline]
124 fn chain_rule(&self, f0: T, f1: T, f2: T) -> Self {
125 Self::new(
126 f0,
127 &self.v1 * f1.clone(),
128 &self.v2 * f1 + self.v1.tr_mul(&self.v1) * f2,
129 )
130 }
131}
132
133impl<T: DualNum<F>, F: Float, D: Dim> Mul<&Dual2Vec<T, F, D>> for &Dual2Vec<T, F, D>
135where
136 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
137{
138 type Output = Dual2Vec<T, F, D>;
139 #[inline]
140 fn mul(self, other: &Dual2Vec<T, F, D>) -> Dual2Vec<T, F, D> {
141 Dual2Vec::new(
142 self.re.clone() * other.re.clone(),
143 &other.v1 * self.re.clone() + &self.v1 * other.re.clone(),
144 &other.v2 * self.re.clone()
145 + self.v1.tr_mul(&other.v1)
146 + other.v1.tr_mul(&self.v1)
147 + &self.v2 * other.re.clone(),
148 )
149 }
150}
151
152impl<T: DualNum<F>, F: Float, D: Dim> Div<&Dual2Vec<T, F, D>> for &Dual2Vec<T, F, D>
154where
155 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
156{
157 type Output = Dual2Vec<T, F, D>;
158 #[inline]
159 fn div(self, other: &Dual2Vec<T, F, D>) -> Dual2Vec<T, F, D> {
160 let inv = other.re.recip();
161 let inv2 = inv.clone() * inv.clone();
162 Dual2Vec::new(
163 self.re.clone() * inv.clone(),
164 (&self.v1 * other.re.clone() - &other.v1 * self.re.clone()) * inv2.clone(),
165 &self.v2 * inv.clone()
166 - (&other.v2 * self.re.clone()
167 + self.v1.tr_mul(&other.v1)
168 + other.v1.tr_mul(&self.v1))
169 * inv2.clone()
170 + other.v1.tr_mul(&other.v1)
171 * ((T::one() + T::one()) * self.re.clone() * inv2 * inv),
172 )
173 }
174}
175
176impl<T: DualNum<F>, F: fmt::Display, D: Dim> fmt::Display for Dual2Vec<T, F, D>
178where
179 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
180{
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 write!(f, "{}", self.re)?;
183 self.v1.fmt(f, "ε1")?;
184 self.v2.fmt(f, "ε1²")
185 }
186}
187
188impl_second_derivatives!(Dual2Vec, [v1, v2], [D], [U1, D], [D, D]);
189impl_dual!(Dual2Vec, [v1, v2], [D], [U1, D], [D, D]);
190
191impl<T, D: Dim> nalgebra::SimdValue for Dual2Vec<T, T::Element, D>
210where
211 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
212 T: DualNum<T::Element> + SimdValue + Scalar,
213 T::Element: DualNum<T::Element> + Scalar,
214{
215 type Element = Dual2Vec<T::Element, T::Element, D>;
224 type SimdBool = T::SimdBool;
225
226 const LANES: usize = T::LANES;
227
228 #[inline]
229 fn splat(val: Self::Element) -> Self {
230 let re = T::splat(val.re);
234 let v1 = Derivative::splat(val.v1);
235 let v2 = Derivative::splat(val.v2);
236 Self::new(re, v1, v2)
237 }
238
239 #[inline]
240 fn extract(&self, i: usize) -> Self::Element {
241 let re = self.re.extract(i);
242 let v1 = self.v1.extract(i);
243 let v2 = self.v2.extract(i);
244 Self::Element {
245 re,
246 v1,
247 v2,
248 f: PhantomData,
249 }
250 }
251
252 #[inline]
253 unsafe fn extract_unchecked(&self, i: usize) -> Self::Element {
254 let re = unsafe { self.re.extract_unchecked(i) };
255 let v1 = unsafe { self.v1.extract_unchecked(i) };
256 let v2 = unsafe { self.v2.extract_unchecked(i) };
257 Self::Element {
258 re,
259 v1,
260 v2,
261 f: PhantomData,
262 }
263 }
264
265 #[inline]
266 fn replace(&mut self, i: usize, val: Self::Element) {
267 self.re.replace(i, val.re);
268 self.v1.replace(i, val.v1);
269 self.v2.replace(i, val.v2);
270 }
271
272 #[inline]
273 unsafe fn replace_unchecked(&mut self, i: usize, val: Self::Element) {
274 unsafe { self.re.replace_unchecked(i, val.re) };
275 unsafe { self.v1.replace_unchecked(i, val.v1) };
276 unsafe { self.v2.replace_unchecked(i, val.v2) };
277 }
278
279 #[inline]
280 fn select(self, cond: Self::SimdBool, other: Self) -> Self {
281 let re = self.re.select(cond, other.re);
282 let v1 = self.v1.select(cond, other.v1);
283 let v2 = self.v2.select(cond, other.v2);
284 Self::new(re, v1, v2)
285 }
286}
287
288impl<T: DualNum<F> + approx::AbsDiffEq<Epsilon = T>, F: Float, D: Dim> approx::AbsDiffEq
291 for Dual2Vec<T, F, D>
292where
293 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
294{
295 type Epsilon = Self;
296 #[inline]
297 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
298 self.re.abs_diff_eq(&other.re, epsilon.re)
299 }
300
301 #[inline]
302 fn default_epsilon() -> Self::Epsilon {
303 Self::from_re(T::default_epsilon())
304 }
305}
306impl<T: DualNum<F> + approx::RelativeEq<Epsilon = T>, F: Float, D: Dim> approx::RelativeEq
309 for Dual2Vec<T, F, D>
310where
311 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
312{
313 #[inline]
314 fn default_max_relative() -> Self::Epsilon {
315 Self::from_re(T::default_max_relative())
316 }
317
318 #[inline]
319 fn relative_eq(
320 &self,
321 other: &Self,
322 epsilon: Self::Epsilon,
323 max_relative: Self::Epsilon,
324 ) -> bool {
325 self.re.relative_eq(&other.re, epsilon.re, max_relative.re)
326 }
327}
328impl<T: DualNum<F> + UlpsEq<Epsilon = T>, F: Float, D: Dim> UlpsEq for Dual2Vec<T, F, D>
329where
330 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
331{
332 #[inline]
333 fn default_max_ulps() -> u32 {
334 T::default_max_ulps()
335 }
336
337 #[inline]
338 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
339 T::ulps_eq(&self.re, &other.re, epsilon.re, max_ulps)
340 }
341}
342
343impl<T, D: Dim> nalgebra::Field for Dual2Vec<T, T::Element, D>
344where
345 T: DualNum<T::Element> + SimdValue,
346 T::Element: DualNum<T::Element> + Scalar + Float,
347 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
348{
349}
350
351use simba::scalar::{SubsetOf, SupersetOf};
352
353impl<TSuper, FSuper, T, F, D: Dim> SubsetOf<Dual2Vec<TSuper, FSuper, D>> for Dual2Vec<T, F, D>
354where
355 TSuper: DualNum<FSuper> + SupersetOf<T>,
356 T: DualNum<F>,
357 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
358{
359 #[inline(always)]
360 fn to_superset(&self) -> Dual2Vec<TSuper, FSuper, D> {
361 let re = TSuper::from_subset(&self.re);
362 let v1 = Derivative::from_subset(&self.v1);
363 let v2 = Derivative::from_subset(&self.v2);
364 Dual2Vec {
365 re,
366 v1,
367 v2,
368 f: PhantomData,
369 }
370 }
371 #[inline(always)]
372 fn from_superset(element: &Dual2Vec<TSuper, FSuper, D>) -> Option<Self> {
373 let re = TSuper::to_subset(&element.re)?;
374 let v1 = Derivative::to_subset(&element.v1)?;
375 let v2 = Derivative::to_subset(&element.v2)?;
376 Some(Self::new(re, v1, v2))
377 }
378 #[inline(always)]
379 fn from_superset_unchecked(element: &Dual2Vec<TSuper, FSuper, D>) -> Self {
380 let re = TSuper::to_subset_unchecked(&element.re);
381 let v1 = Derivative::to_subset_unchecked(&element.v1);
382 let v2 = Derivative::to_subset_unchecked(&element.v2);
383 Self::new(re, v1, v2)
384 }
385 #[inline(always)]
386 fn is_in_subset(element: &Dual2Vec<TSuper, FSuper, D>) -> bool {
387 TSuper::is_in_subset(&element.re)
388 && <Derivative<_, _, _, _> as SupersetOf<Derivative<_, _, _, _>>>::is_in_subset(
389 &element.v1,
390 )
391 && <Derivative<_, _, _, _> as SupersetOf<Derivative<_, _, _, _>>>::is_in_subset(
392 &element.v2,
393 )
394 }
395}
396
397impl<TSuper, FSuper, D: Dim> SupersetOf<f32> for Dual2Vec<TSuper, FSuper, D>
398where
399 TSuper: DualNum<FSuper> + SupersetOf<f32>,
400 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
401{
402 #[inline(always)]
403 fn is_in_subset(&self) -> bool {
404 self.re.is_in_subset()
405 }
406
407 #[inline(always)]
408 fn to_subset_unchecked(&self) -> f32 {
409 self.re.to_subset_unchecked()
410 }
411
412 #[inline(always)]
413 fn from_subset(element: &f32) -> Self {
414 let re = TSuper::from_subset(element);
416 let v1 = Derivative::none();
417 let v2 = Derivative::none();
418 Self::new(re, v1, v2)
419 }
420}
421
422impl<TSuper, FSuper, D: Dim> SupersetOf<f64> for Dual2Vec<TSuper, FSuper, D>
423where
424 TSuper: DualNum<FSuper> + SupersetOf<f64>,
425 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
426{
427 #[inline(always)]
428 fn is_in_subset(&self) -> bool {
429 self.re.is_in_subset()
430 }
431
432 #[inline(always)]
433 fn to_subset_unchecked(&self) -> f64 {
434 self.re.to_subset_unchecked()
435 }
436
437 #[inline(always)]
438 fn from_subset(element: &f64) -> Self {
439 let re = TSuper::from_subset(element);
441 let v1 = Derivative::none();
442 let v2 = Derivative::none();
443 Self::new(re, v1, v2)
444 }
445}
446
447use nalgebra::{ComplexField, RealField};
455impl<T, D: Dim> ComplexField for Dual2Vec<T, T::Element, D>
457where
458 T: DualNum<T::Element> + SupersetOf<T> + AbsDiffEq<Epsilon = T> + Sync + Send,
459 T::Element: DualNum<T::Element> + Scalar + DualNumFloat + Sync + Send,
460 T: SupersetOf<T::Element>,
461 T: SupersetOf<f32>,
462 T: SupersetOf<f64>,
463 T: SimdPartialOrd + PartialOrd,
464 T: SimdValue<Element = T, SimdBool = bool>,
465 T: RelativeEq + UlpsEq + AbsDiffEq,
466 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
467 <DefaultAllocator as Allocator<D>>::Buffer<T>: Sync + Send,
468 <DefaultAllocator as Allocator<U1, D>>::Buffer<T>: Sync + Send,
469 <DefaultAllocator as Allocator<D, U1>>::Buffer<T>: Sync + Send,
470 <DefaultAllocator as Allocator<D, D>>::Buffer<T>: Sync + Send,
471{
472 type RealField = Self;
473
474 #[inline]
475 fn from_real(re: Self::RealField) -> Self {
476 re
477 }
478
479 #[inline]
480 fn real(self) -> Self::RealField {
481 self
482 }
483
484 #[inline]
485 fn imaginary(self) -> Self::RealField {
486 Self::zero()
487 }
488
489 #[inline]
490 fn modulus(self) -> Self::RealField {
491 self.abs()
492 }
493
494 #[inline]
495 fn modulus_squared(self) -> Self::RealField {
496 &self * &self
497 }
498
499 #[inline]
500 fn argument(self) -> Self::RealField {
501 Self::zero()
502 }
503
504 #[inline]
505 fn norm1(self) -> Self::RealField {
506 self.abs()
507 }
508
509 #[inline]
510 fn scale(self, factor: Self::RealField) -> Self {
511 self * factor
512 }
513
514 #[inline]
515 fn unscale(self, factor: Self::RealField) -> Self {
516 self / factor
517 }
518
519 #[inline]
520 fn floor(self) -> Self {
521 panic!("called floor() on a dual number")
522 }
523
524 #[inline]
525 fn ceil(self) -> Self {
526 panic!("called ceil() on a dual number")
527 }
528
529 #[inline]
530 fn round(self) -> Self {
531 panic!("called round() on a dual number")
532 }
533
534 #[inline]
535 fn trunc(self) -> Self {
536 panic!("called trunc() on a dual number")
537 }
538
539 #[inline]
540 fn fract(self) -> Self {
541 panic!("called fract() on a dual number")
542 }
543
544 #[inline]
545 fn mul_add(self, a: Self, b: Self) -> Self {
546 DualNum::mul_add(&self, a, b)
547 }
548
549 #[inline]
550 fn abs(self) -> Self::RealField {
551 Signed::abs(&self)
552 }
553
554 #[inline]
555 fn hypot(self, other: Self) -> Self::RealField {
556 let sum_sq = self.powi(2) + other.powi(2);
557 DualNum::sqrt(&sum_sq)
558 }
559
560 #[inline]
561 fn recip(self) -> Self {
562 DualNum::recip(&self)
563 }
564
565 #[inline]
566 fn conjugate(self) -> Self {
567 self
568 }
569
570 #[inline]
571 fn sin(self) -> Self {
572 DualNum::sin(&self)
573 }
574
575 #[inline]
576 fn cos(self) -> Self {
577 DualNum::cos(&self)
578 }
579
580 #[inline]
581 fn sin_cos(self) -> (Self, Self) {
582 DualNum::sin_cos(&self)
583 }
584
585 #[inline]
586 fn tan(self) -> Self {
587 DualNum::tan(&self)
588 }
589
590 #[inline]
591 fn asin(self) -> Self {
592 DualNum::asin(&self)
593 }
594
595 #[inline]
596 fn acos(self) -> Self {
597 DualNum::acos(&self)
598 }
599
600 #[inline]
601 fn atan(self) -> Self {
602 DualNum::atan(&self)
603 }
604
605 #[inline]
606 fn sinh(self) -> Self {
607 DualNum::sinh(&self)
608 }
609
610 #[inline]
611 fn cosh(self) -> Self {
612 DualNum::cosh(&self)
613 }
614
615 #[inline]
616 fn tanh(self) -> Self {
617 DualNum::tanh(&self)
618 }
619
620 #[inline]
621 fn asinh(self) -> Self {
622 DualNum::asinh(&self)
623 }
624
625 #[inline]
626 fn acosh(self) -> Self {
627 DualNum::acosh(&self)
628 }
629
630 #[inline]
631 fn atanh(self) -> Self {
632 DualNum::atanh(&self)
633 }
634
635 #[inline]
636 fn log(self, base: Self::RealField) -> Self {
637 DualNum::ln(&self) / DualNum::ln(&base)
638 }
639
640 #[inline]
641 fn log2(self) -> Self {
642 DualNum::log2(&self)
643 }
644
645 #[inline]
646 fn log10(self) -> Self {
647 DualNum::log10(&self)
648 }
649
650 #[inline]
651 fn ln(self) -> Self {
652 DualNum::ln(&self)
653 }
654
655 #[inline]
656 fn ln_1p(self) -> Self {
657 DualNum::ln_1p(&self)
658 }
659
660 #[inline]
661 fn sqrt(self) -> Self {
662 DualNum::sqrt(&self)
663 }
664
665 #[inline]
666 fn exp(self) -> Self {
667 DualNum::exp(&self)
668 }
669
670 #[inline]
671 fn exp2(self) -> Self {
672 DualNum::exp2(&self)
673 }
674
675 #[inline]
676 fn exp_m1(self) -> Self {
677 DualNum::exp_m1(&self)
678 }
679
680 #[inline]
681 fn powi(self, n: i32) -> Self {
682 DualNum::powi(&self, n)
683 }
684
685 #[inline]
686 fn powf(self, n: Self::RealField) -> Self {
687 DualNum::powd(&self, n)
689 }
690
691 #[inline]
692 fn powc(self, n: Self) -> Self {
693 self.powf(n)
695 }
696
697 #[inline]
698 fn cbrt(self) -> Self {
699 DualNum::cbrt(&self)
700 }
701
702 #[inline]
703 fn is_finite(&self) -> bool {
704 self.re.is_finite()
705 }
706
707 #[inline]
708 fn try_sqrt(self) -> Option<Self> {
709 if self > Self::zero() {
710 Some(DualNum::sqrt(&self))
711 } else {
712 None
713 }
714 }
715}
716
717impl<T, D: Dim> RealField for Dual2Vec<T, T::Element, D>
718where
719 T: DualNum<T::Element> + SupersetOf<T> + Sync + Send,
720 T::Element: DualNum<T::Element> + Scalar + DualNumFloat,
721 T: SupersetOf<T::Element>,
722 T: SupersetOf<f32>,
723 T: SupersetOf<f64>,
724 T: SimdPartialOrd + PartialOrd,
725 T: RelativeEq + AbsDiffEq<Epsilon = T>,
726 T: SimdValue<Element = T, SimdBool = bool>,
727 T: UlpsEq,
728 T: AbsDiffEq,
729 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
730 <DefaultAllocator as Allocator<D>>::Buffer<T>: Sync + Send,
731 <DefaultAllocator as Allocator<U1, D>>::Buffer<T>: Sync + Send,
732 <DefaultAllocator as Allocator<D, U1>>::Buffer<T>: Sync + Send,
733 <DefaultAllocator as Allocator<D, D>>::Buffer<T>: Sync + Send,
734{
735 #[inline]
736 fn copysign(self, sign: Self) -> Self {
737 if sign.re.is_sign_positive() {
738 self.simd_abs()
739 } else {
740 -self.simd_abs()
741 }
742 }
743
744 #[inline]
745 fn atan2(self, other: Self) -> Self {
746 DualNum::atan2(&self, other)
747 }
748
749 #[inline]
750 fn pi() -> Self {
751 Self::from_re(<T as FloatConst>::PI())
752 }
753
754 #[inline]
755 fn two_pi() -> Self {
756 Self::from_re(<T as FloatConst>::TAU())
757 }
758
759 #[inline]
760 fn frac_pi_2() -> Self {
761 Self::from_re(<T as FloatConst>::FRAC_PI_4())
762 }
763
764 #[inline]
765 fn frac_pi_3() -> Self {
766 Self::from_re(<T as FloatConst>::FRAC_PI_3())
767 }
768
769 #[inline]
770 fn frac_pi_4() -> Self {
771 Self::from_re(<T as FloatConst>::FRAC_PI_4())
772 }
773
774 #[inline]
775 fn frac_pi_6() -> Self {
776 Self::from_re(<T as FloatConst>::FRAC_PI_6())
777 }
778
779 #[inline]
780 fn frac_pi_8() -> Self {
781 Self::from_re(<T as FloatConst>::FRAC_PI_8())
782 }
783
784 #[inline]
785 fn frac_1_pi() -> Self {
786 Self::from_re(<T as FloatConst>::FRAC_1_PI())
787 }
788
789 #[inline]
790 fn frac_2_pi() -> Self {
791 Self::from_re(<T as FloatConst>::FRAC_2_PI())
792 }
793
794 #[inline]
795 fn frac_2_sqrt_pi() -> Self {
796 Self::from_re(<T as FloatConst>::FRAC_2_SQRT_PI())
797 }
798
799 #[inline]
800 fn e() -> Self {
801 Self::from_re(<T as FloatConst>::E())
802 }
803
804 #[inline]
805 fn log2_e() -> Self {
806 Self::from_re(<T as FloatConst>::LOG2_E())
807 }
808
809 #[inline]
810 fn log10_e() -> Self {
811 Self::from_re(<T as FloatConst>::LOG10_E())
812 }
813
814 #[inline]
815 fn ln_2() -> Self {
816 Self::from_re(<T as FloatConst>::LN_2())
817 }
818
819 #[inline]
820 fn ln_10() -> Self {
821 Self::from_re(<T as FloatConst>::LN_10())
822 }
823
824 #[inline]
825 fn is_sign_positive(&self) -> bool {
826 self.re.is_sign_positive()
827 }
828
829 #[inline]
830 fn is_sign_negative(&self) -> bool {
831 self.re.is_sign_negative()
832 }
833
834 #[inline]
836 fn max(self, other: Self) -> Self {
837 if other > self { other } else { self }
838 }
839
840 #[inline]
842 fn min(self, other: Self) -> Self {
843 if other < self { other } else { self }
844 }
845
846 #[inline]
848 fn clamp(self, min: Self, max: Self) -> Self {
849 if self < min {
850 min
851 } else if self > max {
852 max
853 } else {
854 self
855 }
856 }
857
858 #[inline]
859 fn min_value() -> Option<Self> {
860 Some(Self::from_re(T::min_value()))
861 }
862
863 #[inline]
864 fn max_value() -> Option<Self> {
865 Some(Self::from_re(T::max_value()))
866 }
867}