From 55cf3bc7d8c478901632ca14b1b527082041b5db Mon Sep 17 00:00:00 2001 From: Jacob Hegna Date: Wed, 23 Apr 2014 19:46:19 -0500 Subject: [PATCH 1/5] Added a fast_rsqrt function to compute, well, fast inverse square roots. It uses the Newton's method approach originally seen in Quake Arena --- src/libstd/num/f32.rs | 17 +++++++++++++++++ src/libstd/num/f64.rs | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index bf31f36d22d25..3f428fb5002fe 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -456,6 +456,23 @@ impl Float for f32 { #[inline] fn rsqrt(self) -> f32 { self.sqrt().recip() } + /// The reciprocal of the square root of a number, quickly using + /// Newton's method to approximate the value. + /// Originally seen in Quake arena + fn fast_rsqrt(self) -> f32 { + let mut i: i32 = 0; + let mut x2: f32 = 0.0; + let mut y: f32 = 0.0; + + y = self; + x2 = y * 0.5; + i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit level hacking + i = 0x5f3759df - ( i >> 1 ); + y = unsafe{std::cast::transmute::(i)}; + y = y * (1.5 - (x2 * y * y)); + y + } + #[inline] fn cbrt(self) -> f32 { unsafe { cmath::cbrtf(self) } diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 39eba0825fc3c..5551b122b4c50 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -464,6 +464,28 @@ impl Float for f64 { #[inline] fn rsqrt(self) -> f64 { self.sqrt().recip() } + /// The reciprocal of the square root of a number, quickly using + /// Newton's method to approximate the value. For f64 values, + /// the calculations are still done with 32 bit precision due to + /// the math not working the same way in higher bit types. If you're + /// calculating the "fast" inverse square root, however, this should + /// not be a major problem + /// Originally seen in Quake arena + fn fast_rsqrt(self) -> f64 { + let mut i: i32 = 0; + let mut x2: f32 = 0.0; + let mut y: f32 = 0.0; + + y = self as f32; + x2 = y * 0.5; + i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit level hacking + i = 0x5f3759df - ( i >> 1 ); + y = unsafe{std::cast::transmute::(i)}; + y = y * (1.5 - (x2 * y * y)); + y as f64 + } + + #[inline] fn cbrt(self) -> f64 { unsafe { cmath::cbrt(self) } From 9d1b8a06722de3207cc19330e8e35381e952fbdd Mon Sep 17 00:00:00 2001 From: Jacob Hegna Date: Wed, 23 Apr 2014 19:55:24 -0500 Subject: [PATCH 2/5] Made lines in f32.rs and f64.rs shorter than 100 chars --- src/libstd/num/f32.rs | 4 ++-- src/libstd/num/f64.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 3f428fb5002fe..cbe3a63aa31ea 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -466,8 +466,8 @@ impl Float for f32 { y = self; x2 = y * 0.5; - i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit level hacking - i = 0x5f3759df - ( i >> 1 ); + i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit + i = 0x5f3759df - ( i >> 1 ); // level hacking y = unsafe{std::cast::transmute::(i)}; y = y * (1.5 - (x2 * y * y)); y diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 5551b122b4c50..02a662af97d9f 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -478,8 +478,8 @@ impl Float for f64 { y = self as f32; x2 = y * 0.5; - i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit level hacking - i = 0x5f3759df - ( i >> 1 ); + i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit + i = 0x5f3759df - ( i >> 1 ); // level hacking y = unsafe{std::cast::transmute::(i)}; y = y * (1.5 - (x2 * y * y)); y as f64 From fe6f66322cfbada5ea1fa7cf4fdf995cae083937 Mon Sep 17 00:00:00 2001 From: Jacob Hegna Date: Wed, 23 Apr 2014 20:00:30 -0500 Subject: [PATCH 3/5] eliminated the std:: prepended to transmute calls that originated from testing the function --- src/libstd/num/f32.rs | 4 ++-- src/libstd/num/f64.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index cbe3a63aa31ea..0c1b0190fbd03 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -466,9 +466,9 @@ impl Float for f32 { y = self; x2 = y * 0.5; - i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit + i = unsafe{cast::transmute::(y)}; // stark lack of evil floating point bit i = 0x5f3759df - ( i >> 1 ); // level hacking - y = unsafe{std::cast::transmute::(i)}; + y = unsafe{cast::transmute::(i)}; y = y * (1.5 - (x2 * y * y)); y } diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 02a662af97d9f..7481307a4b967 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -478,9 +478,9 @@ impl Float for f64 { y = self as f32; x2 = y * 0.5; - i = unsafe{std::cast::transmute::(y)}; // stark lack of evil floating point bit + i = unsafe{cast::transmute::(y)}; // stark lack of evil floating point bit i = 0x5f3759df - ( i >> 1 ); // level hacking - y = unsafe{std::cast::transmute::(i)}; + y = unsafe{cast::transmute::(i)}; y = y * (1.5 - (x2 * y * y)); y as f64 } From e4e847aec86c16d1887a64d82623788051cdff08 Mon Sep 17 00:00:00 2001 From: Jacob Hegna Date: Wed, 23 Apr 2014 20:06:22 -0500 Subject: [PATCH 4/5] Added fast_rsqrt to Float's traits --- src/libstd/num/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/num/mod.rs b/src/libstd/num/mod.rs index c498892e76cb4..5b0d251b156f1 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num/mod.rs @@ -428,6 +428,8 @@ pub trait Float: Signed + Primitive { fn sqrt(self) -> Self; /// Take the reciprocal (inverse) square root of a number, `1/sqrt(x)`. fn rsqrt(self) -> Self; + /// Take the fast reciprocal (inverse) square root of a number, `1/sqrt(x)` + fn fast_rsqrt(self) -> Self; /// Take the cubic root of a number. fn cbrt(self) -> Self; /// Calculate the length of the hypotenuse of a right-angle triangle given From 1ef5302a8947a875b7e3ccd5979ea0410100fdaa Mon Sep 17 00:00:00 2001 From: Jacob Hegna Date: Wed, 23 Apr 2014 20:23:44 -0500 Subject: [PATCH 5/5] removed dead assignment --- src/libstd/num/f32.rs | 6 +++--- src/libstd/num/f64.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 0c1b0190fbd03..c8162f90fd775 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -460,9 +460,9 @@ impl Float for f32 { /// Newton's method to approximate the value. /// Originally seen in Quake arena fn fast_rsqrt(self) -> f32 { - let mut i: i32 = 0; - let mut x2: f32 = 0.0; - let mut y: f32 = 0.0; + let mut i: i32; + let mut x2: f32; + let mut y: f32; y = self; x2 = y * 0.5; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 7481307a4b967..75fb4e263e8b5 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -472,9 +472,9 @@ impl Float for f64 { /// not be a major problem /// Originally seen in Quake arena fn fast_rsqrt(self) -> f64 { - let mut i: i32 = 0; - let mut x2: f32 = 0.0; - let mut y: f32 = 0.0; + let mut i: i32; + let mut x2: f32; + let mut y: f32; y = self as f32; x2 = y * 0.5;