2018-05-19 21:41:58 +08:00
use approx ::{ AbsDiffEq , RelativeEq , UlpsEq } ;
2016-12-05 05:44:42 +08:00
use num_complex ::Complex ;
2018-05-19 21:41:58 +08:00
use std ::fmt ;
2016-12-05 05:44:42 +08:00
2020-03-21 19:16:46 +08:00
use crate ::base ::{ Matrix2 , Matrix3 , Normed , Unit , Vector1 , Vector2 } ;
use crate ::geometry ::{ Point2 , Rotation2 } ;
2020-12-18 18:38:33 +08:00
use crate ::Scalar ;
2020-03-21 19:16:46 +08:00
use simba ::scalar ::RealField ;
use simba ::simd ::SimdRealField ;
2020-12-18 18:38:33 +08:00
use std ::cmp ::{ Eq , PartialEq } ;
2016-12-05 05:44:42 +08:00
2020-11-21 18:56:24 +08:00
/// A 2D rotation represented as a complex number with magnitude 1.
///
/// All the methods specific [`UnitComplex`](crate::UnitComplex) are listed here. You may also
/// read the documentation of the [`Complex`](crate::Complex) type which
/// is used internally and accessible with `unit_complex.complex()`.
///
/// # Construction
/// * [Identity <span style="float:right;">`identity`</span>](#identity)
/// * [From a 2D rotation angle <span style="float:right;">`new`, `from_cos_sin_unchecked`…</span>](#construction-from-a-2d-rotation-angle)
/// * [From an existing 2D matrix or complex number <span style="float:right;">`from_matrix`, `rotation_to`, `powf`…</span>](#construction-from-an-existing-2d-matrix-or-complex-number)
/// * [From two vectors <span style="float:right;">`rotation_between`, `scaled_rotation_between_axis`…</span>](#construction-from-two-vectors)
///
/// # Transformation and composition
/// * [Angle extraction <span style="float:right;">`angle`, `angle_to`…</span>](#angle-extraction)
/// * [Transformation of a vector or a point <span style="float:right;">`transform_vector`, `inverse_transform_point`…</span>](#transformation-of-a-vector-or-a-point)
/// * [Conjugation and inversion <span style="float:right;">`conjugate`, `inverse_mut`…</span>](#conjugation-and-inversion)
/// * [Interpolation <span style="float:right;">`slerp`…</span>](#interpolation)
///
/// # Conversion
/// * [Conversion to a matrix <span style="float:right;">`to_rotation_matrix`, `to_homogeneous`…</span>](#conversion-to-a-matrix)
2021-04-11 17:00:38 +08:00
pub type UnitComplex < T > = Unit < Complex < T > > ;
2016-12-05 05:44:42 +08:00
2021-04-11 17:00:38 +08:00
impl < T : Scalar + PartialEq > PartialEq for UnitComplex < T > {
2020-12-18 18:38:33 +08:00
#[ inline ]
fn eq ( & self , rhs : & Self ) -> bool {
( * * self ) . eq ( & * * rhs )
}
}
2021-04-11 17:00:38 +08:00
impl < T : Scalar + Eq > Eq for UnitComplex < T > { }
2020-12-18 18:38:33 +08:00
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField > Normed for Complex < T > {
type Norm = T ::SimdRealField ;
2020-03-21 19:16:46 +08:00
#[ inline ]
2021-04-11 17:00:38 +08:00
fn norm ( & self ) -> T ::SimdRealField {
2020-03-21 19:16:46 +08:00
// We don't use `.norm_sqr()` because it requires
// some very strong Num trait requirements.
( self . re * self . re + self . im * self . im ) . simd_sqrt ( )
}
#[ inline ]
2021-04-11 17:00:38 +08:00
fn norm_squared ( & self ) -> T ::SimdRealField {
2020-03-21 19:16:46 +08:00
// We don't use `.norm_sqr()` because it requires
// some very strong Num trait requirements.
self . re * self . re + self . im * self . im
}
#[ inline ]
fn scale_mut ( & mut self , n : Self ::Norm ) {
self . re * = n ;
self . im * = n ;
}
#[ inline ]
fn unscale_mut ( & mut self , n : Self ::Norm ) {
self . re / = n ;
self . im / = n ;
}
}
2020-11-21 18:56:24 +08:00
/// # Angle extraction
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField > UnitComplex < T >
2020-04-06 00:49:48 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-03-22 06:22:55 +08:00
{
2016-12-05 05:44:42 +08:00
/// The rotation angle in `]-pi; pi]` of this unit complex number.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(1.78);
/// assert_eq!(rot.angle(), 1.78);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn angle ( & self ) -> T {
2020-03-22 06:22:55 +08:00
self . im . simd_atan2 ( self . re )
2016-12-05 05:44:42 +08:00
}
2017-08-03 01:37:44 +08:00
/// The sine of the rotation angle.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # use nalgebra::UnitComplex;
/// let angle = 1.78f32;
/// let rot = UnitComplex::new(angle);
/// assert_eq!(rot.sin_angle(), angle.sin());
/// ```
2017-08-03 01:37:44 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn sin_angle ( & self ) -> T {
2017-08-03 01:37:44 +08:00
self . im
}
/// The cosine of the rotation angle.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # use nalgebra::UnitComplex;
/// let angle = 1.78f32;
/// let rot = UnitComplex::new(angle);
/// assert_eq!(rot.cos_angle(),angle.cos());
/// ```
2017-08-03 01:37:44 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn cos_angle ( & self ) -> T {
2017-08-03 01:37:44 +08:00
self . re
}
2016-12-05 05:44:42 +08:00
/// The rotation angle returned as a 1-dimensional vector.
2018-11-05 17:15:49 +08:00
///
/// This is generally used in the context of generic programming. Using
/// the `.angle()` method instead is more common.
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn scaled_axis ( & self ) -> Vector1 < T > {
2016-12-05 05:44:42 +08:00
Vector1 ::new ( self . angle ( ) )
}
2018-03-09 00:30:59 +08:00
/// The rotation axis and angle in ]0, pi] of this complex number.
///
2018-11-05 17:15:49 +08:00
/// This is generally used in the context of generic programming. Using
/// the `.angle()` method instead is more common.
2018-03-09 00:30:59 +08:00
/// Returns `None` if the angle is zero.
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn axis_angle ( & self ) -> Option < ( Unit < Vector1 < T > > , T ) >
2020-04-06 00:49:48 +08:00
where
2021-04-11 17:00:38 +08:00
T : RealField ,
2020-04-06 00:49:48 +08:00
{
2018-03-09 00:30:59 +08:00
let ang = self . angle ( ) ;
if ang . is_zero ( ) {
None
} else if ang . is_sign_negative ( ) {
Some ( ( Unit ::new_unchecked ( Vector1 ::x ( ) ) , - ang ) )
} else {
2021-04-11 17:00:38 +08:00
Some ( ( Unit ::new_unchecked ( - Vector1 ::< T > ::x ( ) ) , ang ) )
2018-03-09 00:30:59 +08:00
}
}
2020-11-21 18:56:24 +08:00
/// The rotation angle needed to make `self` and `other` coincide.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
2020-11-21 18:56:24 +08:00
/// # #[macro_use] extern crate approx;
2018-11-05 17:15:49 +08:00
/// # use nalgebra::UnitComplex;
2020-11-21 18:56:24 +08:00
/// let rot1 = UnitComplex::new(0.1);
/// let rot2 = UnitComplex::new(1.7);
/// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
2018-11-05 17:15:49 +08:00
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn angle_to ( & self , other : & Self ) -> T {
2020-11-21 18:56:24 +08:00
let delta = self . rotation_to ( other ) ;
delta . angle ( )
2016-12-05 05:44:42 +08:00
}
2020-11-21 18:56:24 +08:00
}
2016-12-05 05:44:42 +08:00
2020-11-21 18:56:24 +08:00
/// # Conjugation and inversion
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField > UnitComplex < T >
2020-11-21 18:56:24 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-11-21 18:56:24 +08:00
{
2016-12-05 05:44:42 +08:00
/// Compute the conjugate of this unit complex number.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(1.78);
/// let conj = rot.conjugate();
/// assert_eq!(rot.complex().im, -conj.complex().im);
/// assert_eq!(rot.complex().re, conj.complex().re);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2019-06-06 05:04:04 +08:00
#[ must_use = " Did you mean to use conjugate_mut()? " ]
2016-12-05 05:44:42 +08:00
pub fn conjugate ( & self ) -> Self {
2019-02-17 05:29:41 +08:00
Self ::new_unchecked ( self . conj ( ) )
2016-12-05 05:44:42 +08:00
}
/// Inverts this complex number if it is not zero.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitComplex;
/// let rot = UnitComplex::new(1.2);
/// let inv = rot.inverse();
/// assert_relative_eq!(rot * inv, UnitComplex::identity(), epsilon = 1.0e-6);
/// assert_relative_eq!(inv * rot, UnitComplex::identity(), epsilon = 1.0e-6);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2019-06-06 05:04:04 +08:00
#[ must_use = " Did you mean to use inverse_mut()? " ]
2016-12-05 05:44:42 +08:00
pub fn inverse ( & self ) -> Self {
self . conjugate ( )
}
/// Compute in-place the conjugate of this unit complex number.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitComplex;
/// let angle = 1.7;
/// let rot = UnitComplex::new(angle);
/// let mut conj = UnitComplex::new(angle);
/// conj.conjugate_mut();
/// assert_eq!(rot.complex().im, -conj.complex().im);
/// assert_eq!(rot.complex().re, conj.complex().re);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
pub fn conjugate_mut ( & mut self ) {
let me = self . as_mut_unchecked ( ) ;
me . im = - me . im ;
}
/// Inverts in-place this unit complex number.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::UnitComplex;
/// let angle = 1.7;
/// let mut rot = UnitComplex::new(angle);
/// rot.inverse_mut();
/// assert_relative_eq!(rot * UnitComplex::new(angle), UnitComplex::identity());
/// assert_relative_eq!(UnitComplex::new(angle) * rot, UnitComplex::identity());
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
pub fn inverse_mut ( & mut self ) {
self . conjugate_mut ( )
}
2020-11-21 18:56:24 +08:00
}
2016-12-05 05:44:42 +08:00
2020-11-21 18:56:24 +08:00
/// # Conversion to a matrix
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField > UnitComplex < T >
2020-11-21 18:56:24 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-11-21 18:56:24 +08:00
{
2016-12-05 05:44:42 +08:00
/// Builds the rotation matrix corresponding to this unit complex number.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # use nalgebra::{UnitComplex, Rotation2};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_6);
/// let expected = Rotation2::new(f32::consts::FRAC_PI_6);
/// assert_eq!(rot.to_rotation_matrix(), expected);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn to_rotation_matrix ( & self ) -> Rotation2 < T > {
2017-02-13 01:17:09 +08:00
let r = self . re ;
let i = self . im ;
2016-12-05 05:44:42 +08:00
2018-02-02 19:26:35 +08:00
Rotation2 ::from_matrix_unchecked ( Matrix2 ::new ( r , - i , i , r ) )
2016-12-05 05:44:42 +08:00
}
/// Converts this unit complex number into its equivalent homogeneous transformation matrix.
2018-11-05 17:15:49 +08:00
///
/// # Example
/// ```
/// # use nalgebra::{UnitComplex, Matrix3};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_6);
/// let expected = Matrix3::new(0.8660254, -0.5, 0.0,
/// 0.5, 0.8660254, 0.0,
/// 0.0, 0.0, 1.0);
/// assert_eq!(rot.to_homogeneous(), expected);
/// ```
2016-12-05 05:44:42 +08:00
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn to_homogeneous ( & self ) -> Matrix3 < T > {
2017-02-13 01:17:09 +08:00
self . to_rotation_matrix ( ) . to_homogeneous ( )
2016-12-05 05:44:42 +08:00
}
2020-11-21 18:56:24 +08:00
}
2019-02-25 00:29:27 +08:00
2020-11-21 18:56:24 +08:00
/// # Transformation of a vector or a point
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField > UnitComplex < T >
2020-11-21 18:56:24 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-11-21 18:56:24 +08:00
{
2019-02-25 00:29:27 +08:00
/// Rotate the given point by this unit complex number.
///
2019-03-15 22:50:47 +08:00
/// This is the same as the multiplication `self * pt`.
///
2019-02-25 00:29:27 +08:00
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitComplex, Point2};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let transformed_point = rot.transform_point(&Point2::new(1.0, 2.0));
/// assert_relative_eq!(transformed_point, Point2::new(-2.0, 1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn transform_point ( & self , pt : & Point2 < T > ) -> Point2 < T > {
2019-02-25 00:29:27 +08:00
self * pt
}
/// Rotate the given vector by this unit complex number.
///
2019-03-15 22:50:47 +08:00
/// This is the same as the multiplication `self * v`.
///
2019-02-25 00:29:27 +08:00
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitComplex, Vector2};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let transformed_vector = rot.transform_vector(&Vector2::new(1.0, 2.0));
/// assert_relative_eq!(transformed_vector, Vector2::new(-2.0, 1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn transform_vector ( & self , v : & Vector2 < T > ) -> Vector2 < T > {
2019-02-25 00:29:27 +08:00
self * v
}
/// Rotate the given point by the inverse of this unit complex number.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitComplex, Point2};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let transformed_point = rot.inverse_transform_point(&Point2::new(1.0, 2.0));
/// assert_relative_eq!(transformed_point, Point2::new(2.0, -1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_point ( & self , pt : & Point2 < T > ) -> Point2 < T > {
2020-11-15 23:57:49 +08:00
// TODO: would it be useful performancewise not to call inverse explicitly (i-e. implement
2019-02-25 00:29:27 +08:00
// the inverse transformation explicitly here) ?
self . inverse ( ) * pt
}
/// Rotate the given vector by the inverse of this unit complex number.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitComplex, Vector2};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let transformed_vector = rot.inverse_transform_vector(&Vector2::new(1.0, 2.0));
/// assert_relative_eq!(transformed_vector, Vector2::new(2.0, -1.0), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_vector ( & self , v : & Vector2 < T > ) -> Vector2 < T > {
2019-02-25 00:29:27 +08:00
self . inverse ( ) * v
}
2020-10-25 18:23:34 +08:00
/// Rotate the given vector by the inverse of this unit complex number.
///
/// # Example
/// ```
/// # #[macro_use] extern crate approx;
/// # use nalgebra::{UnitComplex, Vector2};
/// # use std::f32;
/// let rot = UnitComplex::new(f32::consts::FRAC_PI_2);
/// let transformed_vector = rot.inverse_transform_unit_vector(&Vector2::x_axis());
/// assert_relative_eq!(transformed_vector, -Vector2::y_axis(), epsilon = 1.0e-6);
/// ```
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn inverse_transform_unit_vector ( & self , v : & Unit < Vector2 < T > > ) -> Unit < Vector2 < T > > {
2020-10-25 18:23:34 +08:00
self . inverse ( ) * v
}
2020-11-21 18:56:24 +08:00
}
2020-10-25 21:00:47 +08:00
2020-11-21 18:56:24 +08:00
/// # Interpolation
2021-04-11 17:00:38 +08:00
impl < T : SimdRealField > UnitComplex < T >
2020-11-21 18:56:24 +08:00
where
2021-04-11 17:00:38 +08:00
T ::Element : SimdRealField ,
2020-11-21 18:56:24 +08:00
{
2020-10-25 21:00:47 +08:00
/// Spherical linear interpolation between two rotations represented as unit complex numbers.
///
/// # Examples:
///
/// ```
2020-10-25 21:15:26 +08:00
/// # #[macro_use] extern crate approx;
2020-10-25 21:00:47 +08:00
/// # use nalgebra::geometry::UnitComplex;
///
/// let rot1 = UnitComplex::new(std::f32::consts::FRAC_PI_4);
/// let rot2 = UnitComplex::new(-std::f32::consts::PI);
///
/// let rot = rot1.slerp(&rot2, 1.0 / 3.0);
///
2020-10-25 21:15:26 +08:00
/// assert_relative_eq!(rot.angle(), std::f32::consts::FRAC_PI_2);
2020-10-25 21:00:47 +08:00
/// ```
#[ inline ]
2021-06-06 20:46:36 +08:00
#[ must_use = " This function does not mutate self. You should use the return value. " ]
2021-04-11 17:00:38 +08:00
pub fn slerp ( & self , other : & Self , t : T ) -> Self {
Self ::new ( self . angle ( ) * ( T ::one ( ) - t ) + other . angle ( ) * t )
2020-10-25 21:00:47 +08:00
}
2016-12-05 05:44:42 +08:00
}
2021-04-11 17:00:38 +08:00
impl < T : RealField + fmt ::Display > fmt ::Display for UnitComplex < T > {
2016-12-05 05:44:42 +08:00
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( f , " UnitComplex angle: {} " , self . angle ( ) )
}
}
2017-02-13 01:17:09 +08:00
2021-04-11 17:00:38 +08:00
impl < T : RealField > AbsDiffEq for UnitComplex < T > {
type Epsilon = T ;
2017-02-13 01:17:09 +08:00
#[ inline ]
fn default_epsilon ( ) -> Self ::Epsilon {
2021-04-11 17:00:38 +08:00
T ::default_epsilon ( )
2017-02-13 01:17:09 +08:00
}
#[ inline ]
2018-05-19 21:41:58 +08:00
fn abs_diff_eq ( & self , other : & Self , epsilon : Self ::Epsilon ) -> bool {
self . re . abs_diff_eq ( & other . re , epsilon ) & & self . im . abs_diff_eq ( & other . im , epsilon )
2017-02-13 01:17:09 +08:00
}
2018-05-19 21:41:58 +08:00
}
2017-02-13 01:17:09 +08:00
2021-04-11 17:00:38 +08:00
impl < T : RealField > RelativeEq for UnitComplex < T > {
2017-02-13 01:17:09 +08:00
#[ inline ]
2018-05-19 21:41:58 +08:00
fn default_max_relative ( ) -> Self ::Epsilon {
2021-04-11 17:00:38 +08:00
T ::default_max_relative ( )
2017-02-13 01:17:09 +08:00
}
#[ inline ]
2018-02-02 19:26:35 +08:00
fn relative_eq (
& self ,
other : & Self ,
epsilon : Self ::Epsilon ,
max_relative : Self ::Epsilon ,
2020-04-06 00:49:48 +08:00
) -> bool {
2018-02-02 19:26:35 +08:00
self . re . relative_eq ( & other . re , epsilon , max_relative )
& & self . im . relative_eq ( & other . im , epsilon , max_relative )
2017-02-13 01:17:09 +08:00
}
2018-05-19 21:41:58 +08:00
}
2021-04-11 17:00:38 +08:00
impl < T : RealField > UlpsEq for UnitComplex < T > {
2018-05-19 21:41:58 +08:00
#[ inline ]
fn default_max_ulps ( ) -> u32 {
2021-04-11 17:00:38 +08:00
T ::default_max_ulps ( )
2018-05-19 21:41:58 +08:00
}
2017-02-13 01:17:09 +08:00
#[ inline ]
fn ulps_eq ( & self , other : & Self , epsilon : Self ::Epsilon , max_ulps : u32 ) -> bool {
2018-02-02 19:26:35 +08:00
self . re . ulps_eq ( & other . re , epsilon , max_ulps )
& & self . im . ulps_eq ( & other . im , epsilon , max_ulps )
2017-02-13 01:17:09 +08:00
}
2020-03-21 19:16:46 +08:00
}