@@ -1862,6 +1862,35 @@ pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output = Self> {
18621862 /// assert!(abs_difference < 1e-10);
18631863 /// ```
18641864 fn integer_decode ( self ) -> ( u64 , i16 , i8 ) ;
1865+
1866+ /// Returns a number composed of the magnitude of `self` and the sign of
1867+ /// `sign`.
1868+ ///
1869+ /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
1870+ /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
1871+ /// `sign` is returned.
1872+ ///
1873+ /// # Examples
1874+ ///
1875+ /// ```
1876+ /// use num_traits::Float;
1877+ ///
1878+ /// let f = 3.5_f32;
1879+ ///
1880+ /// assert_eq!(f.copysign(0.42), 3.5_f32);
1881+ /// assert_eq!(f.copysign(-0.42), -3.5_f32);
1882+ /// assert_eq!((-f).copysign(0.42), 3.5_f32);
1883+ /// assert_eq!((-f).copysign(-0.42), -3.5_f32);
1884+ ///
1885+ /// assert!(f32::nan().copysign(1.0).is_nan());
1886+ /// ```
1887+ fn copysign ( self , sign : Self ) -> Self {
1888+ if self . is_sign_negative ( ) == sign. is_sign_negative ( ) {
1889+ self
1890+ } else {
1891+ self . neg ( )
1892+ }
1893+ }
18651894}
18661895
18671896#[ cfg( feature = "std" ) ]
@@ -1939,6 +1968,12 @@ macro_rules! float_impl_std {
19391968 Self :: acosh( self ) -> Self ;
19401969 Self :: atanh( self ) -> Self ;
19411970 }
1971+
1972+ #[ cfg( has_copysign) ]
1973+ #[ inline]
1974+ fn copysign( self , sign: Self ) -> Self {
1975+ Self :: copysign( self , sign)
1976+ }
19421977 }
19431978 } ;
19441979}
@@ -2070,6 +2105,7 @@ impl Float for f32 {
20702105 libm:: atanhf as atanh( self ) -> Self ;
20712106 libm:: fmaxf as max( self , other: Self ) -> Self ;
20722107 libm:: fminf as min( self , other: Self ) -> Self ;
2108+ libm:: copysignf as copysign( self , other: Self ) -> Self ;
20732109 }
20742110}
20752111
@@ -2117,6 +2153,7 @@ impl Float for f64 {
21172153 libm:: atanh as atanh( self ) -> Self ;
21182154 libm:: fmax as max( self , other: Self ) -> Self ;
21192155 libm:: fmin as min( self , other: Self ) -> Self ;
2156+ libm:: copysign as copysign( self , sign: Self ) -> Self ;
21202157 }
21212158}
21222159
@@ -2265,4 +2302,50 @@ mod tests {
22652302 check :: < f32 > ( 1e-6 ) ;
22662303 check :: < f64 > ( 1e-12 ) ;
22672304 }
2305+
2306+ #[ test]
2307+ #[ cfg( any( feature = "std" , feature = "libm" ) ) ]
2308+ fn copysign ( ) {
2309+ use float:: Float ;
2310+ test_copysign_generic ( 2.0_f32 , -2.0_f32 , f32:: nan ( ) ) ;
2311+ test_copysign_generic ( 2.0_f64 , -2.0_f64 , f64:: nan ( ) ) ;
2312+ test_copysignf ( 2.0_f32 , -2.0_f32 , f32:: nan ( ) ) ;
2313+ }
2314+
2315+ #[ cfg( any( feature = "std" , feature = "libm" ) ) ]
2316+ fn test_copysignf ( p : f32 , n : f32 , nan : f32 ) {
2317+ use core:: ops:: Neg ;
2318+ use float:: Float ;
2319+
2320+ assert ! ( p. is_sign_positive( ) ) ;
2321+ assert ! ( n. is_sign_negative( ) ) ;
2322+ assert ! ( nan. is_nan( ) ) ;
2323+
2324+ assert_eq ! ( p, Float :: copysign( p, p) ) ;
2325+ assert_eq ! ( p. neg( ) , Float :: copysign( p, n) ) ;
2326+
2327+ assert_eq ! ( n, Float :: copysign( n, n) ) ;
2328+ assert_eq ! ( n. neg( ) , Float :: copysign( n, p) ) ;
2329+
2330+ // FIXME: is_sign... only works on NaN starting in Rust 1.20
2331+ // assert!(Float::copysign(nan, p).is_sign_positive());
2332+ // assert!(Float::copysign(nan, n).is_sign_negative());
2333+ }
2334+
2335+ #[ cfg( any( feature = "std" , feature = "libm" ) ) ]
2336+ fn test_copysign_generic < F : :: float:: Float + :: core:: fmt:: Debug > ( p : F , n : F , nan : F ) {
2337+ assert ! ( p. is_sign_positive( ) ) ;
2338+ assert ! ( n. is_sign_negative( ) ) ;
2339+ assert ! ( nan. is_nan( ) ) ;
2340+
2341+ assert_eq ! ( p, p. copysign( p) ) ;
2342+ assert_eq ! ( p. neg( ) , p. copysign( n) ) ;
2343+
2344+ assert_eq ! ( n, n. copysign( n) ) ;
2345+ assert_eq ! ( n. neg( ) , n. copysign( p) ) ;
2346+
2347+ // FIXME: is_sign... only works on NaN starting in Rust 1.20
2348+ // assert!(nan.copysign(p).is_sign_positive());
2349+ // assert!(nan.copysign(n).is_sign_negative());
2350+ }
22682351}
0 commit comments