From 6430351e7457649d7b6cb50c33a4ab83e33944f8 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Tue, 10 Apr 2018 15:26:14 +0200 Subject: [PATCH 1/3] =?UTF-8?q?Use=20constant=20for=20180/=CF=80=20in=20f3?= =?UTF-8?q?2::to=5Fdegrees?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current `f32::to_degrees` implementation uses a division to calculate 180/π, which causes a loss of precision. Using a constant is still not perfect (implementing a maximally-precise algorithm would come with a high performance cost), but improves precision with a minimal change. This is a backport from [`std`]. [`std`]: https://github.com/rust-lang/rust/pull/47919/commits/e34c31bf02eb0f0ff4dd43ae72e0eae53f2ac519 --- src/float.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/float.rs b/src/float.rs index 072a91b..dbd11d4 100644 --- a/src/float.rs +++ b/src/float.rs @@ -771,7 +771,9 @@ impl FloatCore for f32 { #[inline] #[cfg(not(feature = "std"))] fn to_degrees(self) -> Self { - self * (180.0 / f32::consts::PI) + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 } #[inline] @@ -841,6 +843,9 @@ impl FloatCore for f64 { #[inline] #[cfg(not(feature = "std"))] fn to_degrees(self) -> Self { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) self * (180.0 / f64::consts::PI) } @@ -2008,4 +2013,9 @@ mod tests { assert!((Float::to_radians(deg) - rad).abs() < 1e-5); } } + + #[test] + fn to_degrees_rounding() { + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); + } } From 9ca219c677a68227ce8a483b9e919910d8b833da Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Tue, 10 Apr 2018 19:56:39 +0200 Subject: [PATCH 2/3] Avoid test failure with Rust 1.8 by limiting to no-std builds --- src/float.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/float.rs b/src/float.rs index dbd11d4..830d556 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2015,6 +2015,9 @@ mod tests { } #[test] + // This fails with the forwarded `std` implementation in Rust 1.8. + // To avoid the failure, the test is limited to `no_std` builds. + #[cfg(not(feature = "std"))] fn to_degrees_rounding() { assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); } From 6aaff332d353eb4fb785521a27fe558441e462b0 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Fri, 4 May 2018 12:19:23 -0700 Subject: [PATCH 3/3] Explicitly test FloatCore in to_degrees_rounding --- src/float.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/float.rs b/src/float.rs index 830d556..8df3254 100644 --- a/src/float.rs +++ b/src/float.rs @@ -2019,6 +2019,8 @@ mod tests { // To avoid the failure, the test is limited to `no_std` builds. #[cfg(not(feature = "std"))] fn to_degrees_rounding() { - assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); + use float::FloatCore; + + assert_eq!(FloatCore::to_degrees(1_f32), 57.2957795130823208767981548141051703); } }