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> + PartialEq, F: Float, D: Dim> PartialEq for Dual2Vec<T, F, D>
291where
292 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
293{
294 #[inline]
295 fn eq(&self, other: &Self) -> bool {
296 self.re.eq(&other.re)
297 }
298}
299impl<T: DualNum<F> + PartialOrd, F: Float, D: Dim> PartialOrd for Dual2Vec<T, F, D>
302where
303 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
304{
305 #[inline]
306 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
307 self.re.partial_cmp(&other.re)
308 }
309}
310impl<T: DualNum<F> + approx::AbsDiffEq<Epsilon = T>, F: Float, D: Dim> approx::AbsDiffEq
313 for Dual2Vec<T, F, D>
314where
315 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
316{
317 type Epsilon = Self;
318 #[inline]
319 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
320 self.re.abs_diff_eq(&other.re, epsilon.re)
321 }
322
323 #[inline]
324 fn default_epsilon() -> Self::Epsilon {
325 Self::from_re(T::default_epsilon())
326 }
327}
328impl<T: DualNum<F> + approx::RelativeEq<Epsilon = T>, F: Float, D: Dim> approx::RelativeEq
331 for Dual2Vec<T, F, D>
332where
333 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
334{
335 #[inline]
336 fn default_max_relative() -> Self::Epsilon {
337 Self::from_re(T::default_max_relative())
338 }
339
340 #[inline]
341 fn relative_eq(
342 &self,
343 other: &Self,
344 epsilon: Self::Epsilon,
345 max_relative: Self::Epsilon,
346 ) -> bool {
347 self.re.relative_eq(&other.re, epsilon.re, max_relative.re)
348 }
349}
350impl<T: DualNum<F> + UlpsEq<Epsilon = T>, F: Float, D: Dim> UlpsEq for Dual2Vec<T, F, D>
351where
352 DefaultAllocator: Allocator<U1, D> + Allocator<D, D>,
353{
354 #[inline]
355 fn default_max_ulps() -> u32 {
356 T::default_max_ulps()
357 }
358
359 #[inline]
360 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
361 T::ulps_eq(&self.re, &other.re, epsilon.re, max_ulps)
362 }
363}
364
365impl<T, D: Dim> nalgebra::Field for Dual2Vec<T, T::Element, D>
366where
367 T: DualNum<T::Element> + SimdValue,
368 T::Element: DualNum<T::Element> + Scalar + Float,
369 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
370{
371}
372
373use simba::scalar::{SubsetOf, SupersetOf};
374
375impl<TSuper, FSuper, T, F, D: Dim> SubsetOf<Dual2Vec<TSuper, FSuper, D>> for Dual2Vec<T, F, D>
376where
377 TSuper: DualNum<FSuper> + SupersetOf<T>,
378 T: DualNum<F>,
379 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
380{
381 #[inline(always)]
382 fn to_superset(&self) -> Dual2Vec<TSuper, FSuper, D> {
383 let re = TSuper::from_subset(&self.re);
384 let v1 = Derivative::from_subset(&self.v1);
385 let v2 = Derivative::from_subset(&self.v2);
386 Dual2Vec {
387 re,
388 v1,
389 v2,
390 f: PhantomData,
391 }
392 }
393 #[inline(always)]
394 fn from_superset(element: &Dual2Vec<TSuper, FSuper, D>) -> Option<Self> {
395 let re = TSuper::to_subset(&element.re)?;
396 let v1 = Derivative::to_subset(&element.v1)?;
397 let v2 = Derivative::to_subset(&element.v2)?;
398 Some(Self::new(re, v1, v2))
399 }
400 #[inline(always)]
401 fn from_superset_unchecked(element: &Dual2Vec<TSuper, FSuper, D>) -> Self {
402 let re = TSuper::to_subset_unchecked(&element.re);
403 let v1 = Derivative::to_subset_unchecked(&element.v1);
404 let v2 = Derivative::to_subset_unchecked(&element.v2);
405 Self::new(re, v1, v2)
406 }
407 #[inline(always)]
408 fn is_in_subset(element: &Dual2Vec<TSuper, FSuper, D>) -> bool {
409 TSuper::is_in_subset(&element.re)
410 && <Derivative<_, _, _, _> as SupersetOf<Derivative<_, _, _, _>>>::is_in_subset(
411 &element.v1,
412 )
413 && <Derivative<_, _, _, _> as SupersetOf<Derivative<_, _, _, _>>>::is_in_subset(
414 &element.v2,
415 )
416 }
417}
418
419impl<TSuper, FSuper, D: Dim> SupersetOf<f32> for Dual2Vec<TSuper, FSuper, D>
420where
421 TSuper: DualNum<FSuper> + SupersetOf<f32>,
422 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
423{
424 #[inline(always)]
425 fn is_in_subset(&self) -> bool {
426 self.re.is_in_subset()
427 }
428
429 #[inline(always)]
430 fn to_subset_unchecked(&self) -> f32 {
431 self.re.to_subset_unchecked()
432 }
433
434 #[inline(always)]
435 fn from_subset(element: &f32) -> Self {
436 let re = TSuper::from_subset(element);
438 let v1 = Derivative::none();
439 let v2 = Derivative::none();
440 Self::new(re, v1, v2)
441 }
442}
443
444impl<TSuper, FSuper, D: Dim> SupersetOf<f64> for Dual2Vec<TSuper, FSuper, D>
445where
446 TSuper: DualNum<FSuper> + SupersetOf<f64>,
447 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
448{
449 #[inline(always)]
450 fn is_in_subset(&self) -> bool {
451 self.re.is_in_subset()
452 }
453
454 #[inline(always)]
455 fn to_subset_unchecked(&self) -> f64 {
456 self.re.to_subset_unchecked()
457 }
458
459 #[inline(always)]
460 fn from_subset(element: &f64) -> Self {
461 let re = TSuper::from_subset(element);
463 let v1 = Derivative::none();
464 let v2 = Derivative::none();
465 Self::new(re, v1, v2)
466 }
467}
468
469use nalgebra::{ComplexField, RealField};
477impl<T, D: Dim> ComplexField for Dual2Vec<T, T::Element, D>
479where
480 T: DualNum<T::Element> + SupersetOf<T> + AbsDiffEq<Epsilon = T> + Sync + Send,
481 T::Element: DualNum<T::Element> + Scalar + DualNumFloat + Sync + Send,
482 T: SupersetOf<T::Element>,
483 T: SupersetOf<f32>,
484 T: SupersetOf<f64>,
485 T: SimdPartialOrd + PartialOrd,
486 T: SimdValue<Element = T, SimdBool = bool>,
487 T: RelativeEq + UlpsEq + AbsDiffEq,
488 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
489 <DefaultAllocator as Allocator<D>>::Buffer<T>: Sync + Send,
490 <DefaultAllocator as Allocator<U1, D>>::Buffer<T>: Sync + Send,
491 <DefaultAllocator as Allocator<D, U1>>::Buffer<T>: Sync + Send,
492 <DefaultAllocator as Allocator<D, D>>::Buffer<T>: Sync + Send,
493{
494 type RealField = Self;
495
496 #[inline]
497 fn from_real(re: Self::RealField) -> Self {
498 re
499 }
500
501 #[inline]
502 fn real(self) -> Self::RealField {
503 self
504 }
505
506 #[inline]
507 fn imaginary(self) -> Self::RealField {
508 Self::zero()
509 }
510
511 #[inline]
512 fn modulus(self) -> Self::RealField {
513 self.abs()
514 }
515
516 #[inline]
517 fn modulus_squared(self) -> Self::RealField {
518 &self * &self
519 }
520
521 #[inline]
522 fn argument(self) -> Self::RealField {
523 Self::zero()
524 }
525
526 #[inline]
527 fn norm1(self) -> Self::RealField {
528 self.abs()
529 }
530
531 #[inline]
532 fn scale(self, factor: Self::RealField) -> Self {
533 self * factor
534 }
535
536 #[inline]
537 fn unscale(self, factor: Self::RealField) -> Self {
538 self / factor
539 }
540
541 #[inline]
542 fn floor(self) -> Self {
543 panic!("called floor() on a dual number")
544 }
545
546 #[inline]
547 fn ceil(self) -> Self {
548 panic!("called ceil() on a dual number")
549 }
550
551 #[inline]
552 fn round(self) -> Self {
553 panic!("called round() on a dual number")
554 }
555
556 #[inline]
557 fn trunc(self) -> Self {
558 panic!("called trunc() on a dual number")
559 }
560
561 #[inline]
562 fn fract(self) -> Self {
563 panic!("called fract() on a dual number")
564 }
565
566 #[inline]
567 fn mul_add(self, a: Self, b: Self) -> Self {
568 DualNum::mul_add(&self, a, b)
569 }
570
571 #[inline]
572 fn abs(self) -> Self::RealField {
573 Signed::abs(&self)
574 }
575
576 #[inline]
577 fn hypot(self, other: Self) -> Self::RealField {
578 let sum_sq = self.powi(2) + other.powi(2);
579 DualNum::sqrt(&sum_sq)
580 }
581
582 #[inline]
583 fn recip(self) -> Self {
584 DualNum::recip(&self)
585 }
586
587 #[inline]
588 fn conjugate(self) -> Self {
589 self
590 }
591
592 #[inline]
593 fn sin(self) -> Self {
594 DualNum::sin(&self)
595 }
596
597 #[inline]
598 fn cos(self) -> Self {
599 DualNum::cos(&self)
600 }
601
602 #[inline]
603 fn sin_cos(self) -> (Self, Self) {
604 DualNum::sin_cos(&self)
605 }
606
607 #[inline]
608 fn tan(self) -> Self {
609 DualNum::tan(&self)
610 }
611
612 #[inline]
613 fn asin(self) -> Self {
614 DualNum::asin(&self)
615 }
616
617 #[inline]
618 fn acos(self) -> Self {
619 DualNum::acos(&self)
620 }
621
622 #[inline]
623 fn atan(self) -> Self {
624 DualNum::atan(&self)
625 }
626
627 #[inline]
628 fn sinh(self) -> Self {
629 DualNum::sinh(&self)
630 }
631
632 #[inline]
633 fn cosh(self) -> Self {
634 DualNum::cosh(&self)
635 }
636
637 #[inline]
638 fn tanh(self) -> Self {
639 DualNum::tanh(&self)
640 }
641
642 #[inline]
643 fn asinh(self) -> Self {
644 DualNum::asinh(&self)
645 }
646
647 #[inline]
648 fn acosh(self) -> Self {
649 DualNum::acosh(&self)
650 }
651
652 #[inline]
653 fn atanh(self) -> Self {
654 DualNum::atanh(&self)
655 }
656
657 #[inline]
658 fn log(self, base: Self::RealField) -> Self {
659 DualNum::ln(&self) / DualNum::ln(&base)
660 }
661
662 #[inline]
663 fn log2(self) -> Self {
664 DualNum::log2(&self)
665 }
666
667 #[inline]
668 fn log10(self) -> Self {
669 DualNum::log10(&self)
670 }
671
672 #[inline]
673 fn ln(self) -> Self {
674 DualNum::ln(&self)
675 }
676
677 #[inline]
678 fn ln_1p(self) -> Self {
679 DualNum::ln_1p(&self)
680 }
681
682 #[inline]
683 fn sqrt(self) -> Self {
684 DualNum::sqrt(&self)
685 }
686
687 #[inline]
688 fn exp(self) -> Self {
689 DualNum::exp(&self)
690 }
691
692 #[inline]
693 fn exp2(self) -> Self {
694 DualNum::exp2(&self)
695 }
696
697 #[inline]
698 fn exp_m1(self) -> Self {
699 DualNum::exp_m1(&self)
700 }
701
702 #[inline]
703 fn powi(self, n: i32) -> Self {
704 DualNum::powi(&self, n)
705 }
706
707 #[inline]
708 fn powf(self, n: Self::RealField) -> Self {
709 DualNum::powd(&self, n)
711 }
712
713 #[inline]
714 fn powc(self, n: Self) -> Self {
715 self.powf(n)
717 }
718
719 #[inline]
720 fn cbrt(self) -> Self {
721 DualNum::cbrt(&self)
722 }
723
724 #[inline]
725 fn is_finite(&self) -> bool {
726 self.re.is_finite()
727 }
728
729 #[inline]
730 fn try_sqrt(self) -> Option<Self> {
731 if self > Self::zero() {
732 Some(DualNum::sqrt(&self))
733 } else {
734 None
735 }
736 }
737}
738
739impl<T, D: Dim> RealField for Dual2Vec<T, T::Element, D>
740where
741 T: DualNum<T::Element> + SupersetOf<T> + Sync + Send,
742 T::Element: DualNum<T::Element> + Scalar + DualNumFloat,
743 T: SupersetOf<T::Element>,
744 T: SupersetOf<f32>,
745 T: SupersetOf<f64>,
746 T: SimdPartialOrd + PartialOrd,
747 T: RelativeEq + AbsDiffEq<Epsilon = T>,
748 T: SimdValue<Element = T, SimdBool = bool>,
749 T: UlpsEq,
750 T: AbsDiffEq,
751 DefaultAllocator: Allocator<U1, D> + Allocator<D, U1> + Allocator<D, D>,
752 <DefaultAllocator as Allocator<D>>::Buffer<T>: Sync + Send,
753 <DefaultAllocator as Allocator<U1, D>>::Buffer<T>: Sync + Send,
754 <DefaultAllocator as Allocator<D, U1>>::Buffer<T>: Sync + Send,
755 <DefaultAllocator as Allocator<D, D>>::Buffer<T>: Sync + Send,
756{
757 #[inline]
758 fn copysign(self, sign: Self) -> Self {
759 if sign.re.is_sign_positive() {
760 self.simd_abs()
761 } else {
762 -self.simd_abs()
763 }
764 }
765
766 #[inline]
767 fn atan2(self, other: Self) -> Self {
768 DualNum::atan2(&self, other)
769 }
770
771 #[inline]
772 fn pi() -> Self {
773 Self::from_re(<T as FloatConst>::PI())
774 }
775
776 #[inline]
777 fn two_pi() -> Self {
778 Self::from_re(<T as FloatConst>::TAU())
779 }
780
781 #[inline]
782 fn frac_pi_2() -> Self {
783 Self::from_re(<T as FloatConst>::FRAC_PI_4())
784 }
785
786 #[inline]
787 fn frac_pi_3() -> Self {
788 Self::from_re(<T as FloatConst>::FRAC_PI_3())
789 }
790
791 #[inline]
792 fn frac_pi_4() -> Self {
793 Self::from_re(<T as FloatConst>::FRAC_PI_4())
794 }
795
796 #[inline]
797 fn frac_pi_6() -> Self {
798 Self::from_re(<T as FloatConst>::FRAC_PI_6())
799 }
800
801 #[inline]
802 fn frac_pi_8() -> Self {
803 Self::from_re(<T as FloatConst>::FRAC_PI_8())
804 }
805
806 #[inline]
807 fn frac_1_pi() -> Self {
808 Self::from_re(<T as FloatConst>::FRAC_1_PI())
809 }
810
811 #[inline]
812 fn frac_2_pi() -> Self {
813 Self::from_re(<T as FloatConst>::FRAC_2_PI())
814 }
815
816 #[inline]
817 fn frac_2_sqrt_pi() -> Self {
818 Self::from_re(<T as FloatConst>::FRAC_2_SQRT_PI())
819 }
820
821 #[inline]
822 fn e() -> Self {
823 Self::from_re(<T as FloatConst>::E())
824 }
825
826 #[inline]
827 fn log2_e() -> Self {
828 Self::from_re(<T as FloatConst>::LOG2_E())
829 }
830
831 #[inline]
832 fn log10_e() -> Self {
833 Self::from_re(<T as FloatConst>::LOG10_E())
834 }
835
836 #[inline]
837 fn ln_2() -> Self {
838 Self::from_re(<T as FloatConst>::LN_2())
839 }
840
841 #[inline]
842 fn ln_10() -> Self {
843 Self::from_re(<T as FloatConst>::LN_10())
844 }
845
846 #[inline]
847 fn is_sign_positive(&self) -> bool {
848 self.re.is_sign_positive()
849 }
850
851 #[inline]
852 fn is_sign_negative(&self) -> bool {
853 self.re.is_sign_negative()
854 }
855
856 #[inline]
858 fn max(self, other: Self) -> Self {
859 if other > self { other } else { self }
860 }
861
862 #[inline]
864 fn min(self, other: Self) -> Self {
865 if other < self { other } else { self }
866 }
867
868 #[inline]
870 fn clamp(self, min: Self, max: Self) -> Self {
871 if self < min {
872 min
873 } else if self > max {
874 max
875 } else {
876 self
877 }
878 }
879
880 #[inline]
881 fn min_value() -> Option<Self> {
882 Some(Self::from_re(T::min_value()))
883 }
884
885 #[inline]
886 fn max_value() -> Option<Self> {
887 Some(Self::from_re(T::max_value()))
888 }
889}