@@ -224,21 +224,90 @@ impl<T: Clone + Float> Complex<T> {
224224 if self . re . is_sign_positive ( ) {
225225 // simple positive real √r, and copy `im` for its sign
226226 Self :: new ( self . re . sqrt ( ) , self . im )
227- } else if self . im . is_sign_positive ( ) {
228- // √(r e^(iπ)) = √r e^(iπ/2) = i√r
229- Self :: new ( T :: zero ( ) , self . re . abs ( ) . sqrt ( ) )
230227 } else {
228+ // √(r e^(iπ)) = √r e^(iπ/2) = i√r
231229 // √(r e^(-iπ)) = √r e^(-iπ/2) = -i√r
232- Self :: new ( T :: zero ( ) , -self . re . abs ( ) . sqrt ( ) )
230+ let re = T :: zero ( ) ;
231+ let im = ( -self . re ) . sqrt ( ) ;
232+ if self . im . is_sign_positive ( ) {
233+ Self :: new ( re, im)
234+ } else {
235+ Self :: new ( re, -im)
236+ }
237+ }
238+ } else if self . re . is_zero ( ) {
239+ // √(r e^(iπ/2)) = √r e^(iπ/4) = √(r/2) + i√(r/2)
240+ // √(r e^(-iπ/2)) = √r e^(-iπ/4) = √(r/2) - i√(r/2)
241+ let one = T :: one ( ) ;
242+ let two = one + one;
243+ let x = ( self . im . abs ( ) / two) . sqrt ( ) ;
244+ if self . im . is_sign_positive ( ) {
245+ Self :: new ( x, x)
246+ } else {
247+ Self :: new ( x, -x)
233248 }
234249 } else {
235250 // formula: sqrt(r e^(it)) = sqrt(r) e^(it/2)
236- let two = T :: one ( ) + T :: one ( ) ;
251+ let one = T :: one ( ) ;
252+ let two = one + one;
237253 let ( r, theta) = self . to_polar ( ) ;
238254 Self :: from_polar ( & ( r. sqrt ( ) ) , & ( theta / two) )
239255 }
240256 }
241257
258+ /// Computes the principal value of the cube root of `self`.
259+ ///
260+ /// This function has one branch cut:
261+ ///
262+ /// * `(-∞, 0)`, continuous from above.
263+ ///
264+ /// The branch satisfies `-π/3 ≤ arg(cbrt(z)) ≤ π/3`.
265+ ///
266+ /// Note that this does not match the usual result for the cube root of
267+ /// negative real numbers. For example, the real cube root of `-8` is `-2`,
268+ /// but the principal complex cube root of `-8` is `1 + i√3`.
269+ #[ inline]
270+ pub fn cbrt ( & self ) -> Self {
271+ if self . im . is_zero ( ) {
272+ if self . re . is_sign_positive ( ) {
273+ // simple positive real ∛r, and copy `im` for its sign
274+ Self :: new ( self . re . cbrt ( ) , self . im )
275+ } else {
276+ // ∛(r e^(iπ)) = ∛r e^(iπ/3) = ∛r/2 + i∛r√3/2
277+ // ∛(r e^(-iπ)) = ∛r e^(-iπ/3) = ∛r/2 - i∛r√3/2
278+ let one = T :: one ( ) ;
279+ let two = one + one;
280+ let three = two + one;
281+ let re = ( -self . re ) . cbrt ( ) / two;
282+ let im = three. sqrt ( ) * re;
283+ if self . im . is_sign_positive ( ) {
284+ Self :: new ( re, im)
285+ } else {
286+ Self :: new ( re, -im)
287+ }
288+ }
289+ } else if self . re . is_zero ( ) {
290+ // ∛(r e^(iπ/2)) = ∛r e^(iπ/6) = ∛r√3/2 + i∛r/2
291+ // ∛(r e^(-iπ/2)) = ∛r e^(-iπ/6) = ∛r√3/2 - i∛r/2
292+ let one = T :: one ( ) ;
293+ let two = one + one;
294+ let three = two + one;
295+ let im = self . im . abs ( ) . cbrt ( ) / two;
296+ let re = three. sqrt ( ) * im;
297+ if self . im . is_sign_positive ( ) {
298+ Self :: new ( re, im)
299+ } else {
300+ Self :: new ( re, -im)
301+ }
302+ } else {
303+ // formula: cbrt(r e^(it)) = cbrt(r) e^(it/3)
304+ let one = T :: one ( ) ;
305+ let three = one + one + one;
306+ let ( r, theta) = self . to_polar ( ) ;
307+ Self :: from_polar ( & ( r. cbrt ( ) ) , & ( theta / three) )
308+ }
309+ }
310+
242311 /// Raises `self` to a floating point power.
243312 #[ inline]
244313 pub fn powf ( & self , exp : T ) -> Self {
@@ -1695,8 +1764,8 @@ mod test {
16951764 assert ! ( close( c. conj( ) . sqrt( ) , c. sqrt( ) . conj( ) ) ) ;
16961765 // for this branch, -pi/2 <= arg(sqrt(z)) <= pi/2
16971766 assert ! (
1698- -f64 :: consts:: PI / 2.0 <= c. sqrt( ) . arg( )
1699- && c. sqrt( ) . arg( ) <= f64 :: consts:: PI / 2.0
1767+ -f64 :: consts:: FRAC_PI_2 <= c. sqrt( ) . arg( )
1768+ && c. sqrt( ) . arg( ) <= f64 :: consts:: FRAC_PI_2
17001769 ) ;
17011770 // sqrt(z) * sqrt(z) = z
17021771 assert ! ( close( c. sqrt( ) * c. sqrt( ) , c) ) ;
@@ -1707,11 +1776,95 @@ mod test {
17071776 fn test_sqrt_real ( ) {
17081777 for n in ( 0 ..100 ) . map ( f64:: from) {
17091778 // √(n² + 0i) = n + 0i
1710- assert_eq ! ( Complex64 :: new( n * n, 0.0 ) . sqrt( ) , Complex64 :: new( n, 0.0 ) ) ;
1779+ let n2 = n * n;
1780+ assert_eq ! ( Complex64 :: new( n2, 0.0 ) . sqrt( ) , Complex64 :: new( n, 0.0 ) ) ;
17111781 // √(-n² + 0i) = 0 + ni
1712- assert_eq ! ( Complex64 :: new( -n * n , 0.0 ) . sqrt( ) , Complex64 :: new( 0.0 , n) ) ;
1782+ assert_eq ! ( Complex64 :: new( -n2 , 0.0 ) . sqrt( ) , Complex64 :: new( 0.0 , n) ) ;
17131783 // √(-n² - 0i) = 0 - ni
1714- assert_eq ! ( Complex64 :: new( -n * n, -0.0 ) . sqrt( ) , Complex64 :: new( 0.0 , -n) ) ;
1784+ assert_eq ! ( Complex64 :: new( -n2, -0.0 ) . sqrt( ) , Complex64 :: new( 0.0 , -n) ) ;
1785+ }
1786+ }
1787+
1788+ #[ test]
1789+ fn test_sqrt_imag ( ) {
1790+ for n in ( 0 ..100 ) . map ( f64:: from) {
1791+ // √(0 + n²i) = n e^(iπ/4)
1792+ let n2 = n * n;
1793+ assert ! ( close(
1794+ Complex64 :: new( 0.0 , n2) . sqrt( ) ,
1795+ Complex64 :: from_polar( & n, & ( f64 :: consts:: FRAC_PI_4 ) )
1796+ ) ) ;
1797+ // √(0 - n²i) = n e^(-iπ/4)
1798+ assert ! ( close(
1799+ Complex64 :: new( 0.0 , -n2) . sqrt( ) ,
1800+ Complex64 :: from_polar( & n, & ( -f64 :: consts:: FRAC_PI_4 ) )
1801+ ) ) ;
1802+ }
1803+ }
1804+
1805+ #[ test]
1806+ fn test_cbrt ( ) {
1807+ assert ! ( close( _0_0i. cbrt( ) , _0_0i) ) ;
1808+ assert ! ( close( _1_0i. cbrt( ) , _1_0i) ) ;
1809+ assert ! ( close(
1810+ Complex :: new( -1.0 , 0.0 ) . cbrt( ) ,
1811+ Complex :: new( 0.5 , 0.75 . sqrt( ) )
1812+ ) ) ;
1813+ assert ! ( close(
1814+ Complex :: new( -1.0 , -0.0 ) . cbrt( ) ,
1815+ Complex :: new( 0.5 , -0.75 . sqrt( ) )
1816+ ) ) ;
1817+ assert ! ( close( _0_1i. cbrt( ) , Complex :: new( 0.75 . sqrt( ) , 0.5 ) ) ) ;
1818+ assert ! ( close( _0_1i. conj( ) . cbrt( ) , Complex :: new( 0.75 . sqrt( ) , -0.5 ) ) ) ;
1819+ for & c in all_consts. iter ( ) {
1820+ // cbrt(conj(z() = conj(cbrt(z))
1821+ assert ! ( close( c. conj( ) . cbrt( ) , c. cbrt( ) . conj( ) ) ) ;
1822+ // for this branch, -pi/3 <= arg(cbrt(z)) <= pi/3
1823+ assert ! (
1824+ -f64 :: consts:: FRAC_PI_3 <= c. cbrt( ) . arg( )
1825+ && c. cbrt( ) . arg( ) <= f64 :: consts:: FRAC_PI_3
1826+ ) ;
1827+ // cbrt(z) * cbrt(z) cbrt(z) = z
1828+ assert ! ( close( c. cbrt( ) * c. cbrt( ) * c. cbrt( ) , c) ) ;
1829+ }
1830+ }
1831+
1832+ #[ test]
1833+ fn test_cbrt_real ( ) {
1834+ for n in ( 0 ..100 ) . map ( f64:: from) {
1835+ // ∛(n³ + 0i) = n + 0i
1836+ let n3 = n * n * n;
1837+ assert ! ( close(
1838+ Complex64 :: new( n3, 0.0 ) . cbrt( ) ,
1839+ Complex64 :: new( n, 0.0 )
1840+ ) ) ;
1841+ // ∛(-n³ + 0i) = n e^(iπ/3)
1842+ assert ! ( close(
1843+ Complex64 :: new( -n3, 0.0 ) . cbrt( ) ,
1844+ Complex64 :: from_polar( & n, & ( f64 :: consts:: FRAC_PI_3 ) )
1845+ ) ) ;
1846+ // ∛(-n³ - 0i) = n e^(-iπ/3)
1847+ assert ! ( close(
1848+ Complex64 :: new( -n3, -0.0 ) . cbrt( ) ,
1849+ Complex64 :: from_polar( & n, & ( -f64 :: consts:: FRAC_PI_3 ) )
1850+ ) ) ;
1851+ }
1852+ }
1853+
1854+ #[ test]
1855+ fn test_cbrt_imag ( ) {
1856+ for n in ( 0 ..100 ) . map ( f64:: from) {
1857+ // ∛(0 + n³i) = n e^(iπ/6)
1858+ let n3 = n * n * n;
1859+ assert ! ( close(
1860+ Complex64 :: new( 0.0 , n3) . cbrt( ) ,
1861+ Complex64 :: from_polar( & n, & ( f64 :: consts:: FRAC_PI_6 ) )
1862+ ) ) ;
1863+ // ∛(0 - n³i) = n e^(-iπ/6)
1864+ assert ! ( close(
1865+ Complex64 :: new( 0.0 , -n3) . cbrt( ) ,
1866+ Complex64 :: from_polar( & n, & ( -f64 :: consts:: FRAC_PI_6 ) )
1867+ ) ) ;
17151868 }
17161869 }
17171870
0 commit comments