From f1903ec2a0e5da2eedbd48f8607b88989bc88b8c Mon Sep 17 00:00:00 2001 From: domna Date: Mon, 22 May 2023 14:05:52 +0200 Subject: [PATCH 1/8] Fixes nan value for powc of zero --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1860d28..549309c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -373,6 +373,10 @@ impl Complex { // = p^c e^(−d θ) (cos(c θ + d ln(ρ)) + i sin(c θ + d ln(ρ))) // = from_polar(p^c e^(−d θ), c θ + d ln(ρ)) let (r, theta) = self.to_polar(); + + if r.is_zero() { + return Self::new(r, r); + } Self::from_polar( r.powf(exp.re) * (-exp.im * theta).exp(), exp.re * theta + exp.im * r.ln(), @@ -1908,6 +1912,8 @@ pub(crate) mod test { Complex::new(1.65826, -0.33502), 1e-5 )); + let z = Complex::new(0.0, 0.0); + assert!(close(z.powc(b), z)); } #[test] From 8235bd3aee20949fff60dfdec0c078af9a42c534 Mon Sep 17 00:00:00 2001 From: domna Date: Tue, 23 May 2023 14:29:33 +0200 Subject: [PATCH 2/8] Simplify powc formula --- src/lib.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 549309c..353fd97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -361,26 +361,8 @@ impl Complex { /// Raises `self` to a complex power. #[inline] pub fn powc(self, exp: Self) -> Self { - // formula: x^y = (a + i b)^(c + i d) - // = (ρ e^(i θ))^c (ρ e^(i θ))^(i d) - // where ρ=|x| and θ=arg(x) - // = ρ^c e^(−d θ) e^(i c θ) ρ^(i d) - // = p^c e^(−d θ) (cos(c θ) - // + i sin(c θ)) (cos(d ln(ρ)) + i sin(d ln(ρ))) - // = p^c e^(−d θ) ( - // cos(c θ) cos(d ln(ρ)) − sin(c θ) sin(d ln(ρ)) - // + i(cos(c θ) sin(d ln(ρ)) + sin(c θ) cos(d ln(ρ)))) - // = p^c e^(−d θ) (cos(c θ + d ln(ρ)) + i sin(c θ + d ln(ρ))) - // = from_polar(p^c e^(−d θ), c θ + d ln(ρ)) - let (r, theta) = self.to_polar(); - - if r.is_zero() { - return Self::new(r, r); - } - Self::from_polar( - r.powf(exp.re) * (-exp.im * theta).exp(), - exp.re * theta + exp.im * r.ln(), - ) + // formula: x^y = exp(y * ln(x)) + (exp * self.ln()).exp() } /// Raises a floating point number to the complex power `self`. @@ -1719,6 +1701,9 @@ pub(crate) mod test { #[cfg(any(feature = "std", feature = "libm"))] pub(crate) mod float { + + use core::f64::INFINITY; + use super::*; use num_traits::{Float, Pow}; @@ -1914,6 +1899,11 @@ pub(crate) mod test { )); let z = Complex::new(0.0, 0.0); assert!(close(z.powc(b), z)); + assert!(z.powc(Complex64::new(0., 0.)).is_nan()); + assert!(z.powc(Complex64::new(0., INFINITY)).is_nan()); + assert!(z.powc(Complex64::new(10., INFINITY)).is_nan()); + assert!(z.powc(Complex64::new(INFINITY, INFINITY)).is_nan()); + assert!(close(z.powc(Complex64::new(INFINITY, 0.)), z)); } #[test] From 03a3208c7653d970cf9089a1552afd3c74165f4f Mon Sep 17 00:00:00 2001 From: domna Date: Wed, 24 May 2023 13:11:12 +0200 Subject: [PATCH 3/8] Test for powc(-1) --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 353fd97..1e27cc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1904,6 +1904,8 @@ pub(crate) mod test { assert!(z.powc(Complex64::new(10., INFINITY)).is_nan()); assert!(z.powc(Complex64::new(INFINITY, INFINITY)).is_nan()); assert!(close(z.powc(Complex64::new(INFINITY, 0.)), z)); + assert!(z.powc(Complex64::new(-1., 0.)).re.is_infinite()); + assert!(z.powc(Complex64::new(-1., 0.)).im.is_nan()); } #[test] From d9e8968241a0f15099eb2e79ba77a70cad192235 Mon Sep 17 00:00:00 2001 From: Florian Dobener Date: Tue, 20 Jun 2023 22:46:07 +0200 Subject: [PATCH 4/8] Update src/lib.rs --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 1e27cc2..cb7bb51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1906,6 +1906,8 @@ pub(crate) mod test { assert!(close(z.powc(Complex64::new(INFINITY, 0.)), z)); assert!(z.powc(Complex64::new(-1., 0.)).re.is_infinite()); assert!(z.powc(Complex64::new(-1., 0.)).im.is_nan()); + assert!(z.powc(Complex64::new(-1., 0.)).re.is_infinite()); + assert!(z.powc(Complex64::new(-1., 0.)).im.is_nan()); } #[test] From 21b5ec5fd43a8d792e57b1a1016f425bfa16c421 Mon Sep 17 00:00:00 2001 From: Florian Dobener Date: Thu, 22 Jun 2023 09:15:56 +0200 Subject: [PATCH 5/8] Removes duplicate test --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cb7bb51..1e27cc2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1906,8 +1906,6 @@ pub(crate) mod test { assert!(close(z.powc(Complex64::new(INFINITY, 0.)), z)); assert!(z.powc(Complex64::new(-1., 0.)).re.is_infinite()); assert!(z.powc(Complex64::new(-1., 0.)).im.is_nan()); - assert!(z.powc(Complex64::new(-1., 0.)).re.is_infinite()); - assert!(z.powc(Complex64::new(-1., 0.)).im.is_nan()); } #[test] From 068283b94dac1ebce3654b4ea9a002c3610a6a72 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 11 Aug 2023 16:57:28 -0700 Subject: [PATCH 6/8] powc and powf to zero power => one This is consistent with the standard library powf -- even for NaN! --- src/lib.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1e27cc2..cb847b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -342,6 +342,9 @@ impl Complex { /// Raises `self` to a floating point power. #[inline] pub fn powf(self, exp: T) -> Self { + if exp.is_zero() { + return Self::one(); + } // formula: x^y = (ρ e^(i θ))^y = ρ^y e^(i θ y) // = from_polar(ρ^y, θ y) let (r, theta) = self.to_polar(); @@ -361,6 +364,9 @@ impl Complex { /// Raises `self` to a complex power. #[inline] pub fn powc(self, exp: Self) -> Self { + if exp.is_zero() { + return Self::one(); + } // formula: x^y = exp(y * ln(x)) (exp * self.ln()).exp() } @@ -1899,13 +1905,17 @@ pub(crate) mod test { )); let z = Complex::new(0.0, 0.0); assert!(close(z.powc(b), z)); - assert!(z.powc(Complex64::new(0., 0.)).is_nan()); assert!(z.powc(Complex64::new(0., INFINITY)).is_nan()); assert!(z.powc(Complex64::new(10., INFINITY)).is_nan()); assert!(z.powc(Complex64::new(INFINITY, INFINITY)).is_nan()); assert!(close(z.powc(Complex64::new(INFINITY, 0.)), z)); assert!(z.powc(Complex64::new(-1., 0.)).re.is_infinite()); assert!(z.powc(Complex64::new(-1., 0.)).im.is_nan()); + + for c in all_consts.iter() { + assert_eq!(c.powc(_0_0i), _1_0i); + } + assert_eq!(_nan_nani.powc(_0_0i), _1_0i); } #[test] @@ -1915,6 +1925,11 @@ pub(crate) mod test { assert!(close_to_tol(c.powf(3.5), expected, 1e-5)); assert!(close_to_tol(Pow::pow(c, 3.5_f64), expected, 1e-5)); assert!(close_to_tol(Pow::pow(c, 3.5_f32), expected, 1e-5)); + + for c in all_consts.iter() { + assert_eq!(c.powf(0.0), _1_0i); + } + assert_eq!(_nan_nani.powf(0.0), _1_0i); } #[test] From 450de324074fd2ea9d1f86521747273651a3db90 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 11 Aug 2023 16:20:57 -0700 Subject: [PATCH 7/8] Update CI crate versions --- ci/test_full.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ci/test_full.sh b/ci/test_full.sh index 6cafcc5..60e9740 100755 --- a/ci/test_full.sh +++ b/ci/test_full.sh @@ -38,6 +38,14 @@ cargo generate-lockfile # libm 0.2.6 started using {float}::EPSILON check_version 1.43 || cargo update -p libm --precise 0.2.5 +# Some crates moved to Rust 1.56 / 2021 +check_version 1.56 || ( + cargo update -p quote --precise 1.0.30 + cargo update -p proc-macro2 --precise 1.0.65 + cargo update -p rkyv --precise 0.7.40 + cargo update -p bytecheck --precise 0.6.9 +) + set -x # test the default From 6a593c6d29d26f086a4fa18f3e1f1c45efaf5a46 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Sun, 13 Aug 2023 16:09:57 -0700 Subject: [PATCH 8/8] Release 0.4.4 --- Cargo.toml | 2 +- RELEASES.md | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 149072c..b017e3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ categories = ["algorithms", "data-structures", "science", "no-std"] license = "MIT OR Apache-2.0" name = "num-complex" repository = "https://github.com/rust-num/num-complex" -version = "0.4.3" +version = "0.4.4" readme = "README.md" exclude = ["/bors.toml", "/ci/*", "/.github/*"] edition = "2018" diff --git a/RELEASES.md b/RELEASES.md index d6244d8..1276628 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,9 +1,19 @@ +# Release 0.4.4 (2023-08-13) + +- [Fixes NaN value for `powc` of zero][116] + +**Contributors**: @cuviper, @domna + +[116]: https://github.com/rust-num/num-complex/pull/116 + # Release 0.4.3 (2023-01-19) - [`Complex` now optionally supports `bytecheck` 0.6 and `rkyv` 0.7][110]. **Contributors**: @cuviper, @zyansheep +[110]: https://github.com/rust-num/num-complex/pull/110 + # Release 0.4.2 (2022-06-17) - [The new `ComplexFloat` trait][95] provides a generic abstraction between