From 25d7f0d8b28de5941d8d98e4a3cec43d6b2e7020 Mon Sep 17 00:00:00 2001 From: "Christoph J. Scherr" Date: Mon, 12 Aug 2024 13:21:55 +0200 Subject: [PATCH] revsqrt stuff for PA2 --- members/revsqrt/Cargo.toml | 6 +- .../tests/features/book/revsqrt-demo.feature | 33 ++++++++ members/revsqrt/tests/revsqrt-demo.rs | 82 +++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 members/revsqrt/tests/features/book/revsqrt-demo.feature create mode 100644 members/revsqrt/tests/revsqrt-demo.rs diff --git a/members/revsqrt/Cargo.toml b/members/revsqrt/Cargo.toml index b654fb9..4b70459 100644 --- a/members/revsqrt/Cargo.toml +++ b/members/revsqrt/Cargo.toml @@ -12,7 +12,7 @@ rand = "0.8.5" [[bench]] name = "rsqrt-bench" -harness = false # disable standard harness +harness = false # disable standard harness [lib] name = "revsqrt" @@ -26,6 +26,10 @@ path = "src/main.rs" name = "revsqrt" harness = false # allows Cucumber to print output instead of libtest +[[test]] +name = "revsqrt-demo" +harness = false # allows Cucumber to print output instead of libtest + [[test]] name = "basic-revsqrt" harness = true diff --git a/members/revsqrt/tests/features/book/revsqrt-demo.feature b/members/revsqrt/tests/features/book/revsqrt-demo.feature new file mode 100644 index 0000000..b9c4f02 --- /dev/null +++ b/members/revsqrt/tests/features/book/revsqrt-demo.feature @@ -0,0 +1,33 @@ +Feature: inverted square root calculation + + Scenario: fast inverted sqrt is about the same as the regular inverted sqrt + Given a number + When we calculate the inverted square root of it using the fast inverted square root algorithm + Then the result is about the same as if we calculate it normally + + Scenario: Can the fast inverted sqrt be calculated? + Given a number + When we calculate the inverted square root of it using the fast inverted square root algorithm + Then the result can be calculated + + Scenario: Can the regular inverted sqrt be calculated? + Given a number + When we calculate the inverted square root of it normally + Then the result can be calculated + + Scenario: Calculate regular inverted sqrt with specific numbers + Given the number n + | 1 | + | 1.1 | + | 100 | + | 1337 | + | 123.45678900 | + | 1337.1337 | + When we calculate the inverted square root of it normally + Then the result is m + | 1 | + | 0.9534625892455922 | + | 0.1 | + | 0.02734854943722097 | + | 0.0900000004095 | + | 0.027347182112297627 | diff --git a/members/revsqrt/tests/revsqrt-demo.rs b/members/revsqrt/tests/revsqrt-demo.rs new file mode 100644 index 0000000..7e9780f --- /dev/null +++ b/members/revsqrt/tests/revsqrt-demo.rs @@ -0,0 +1,82 @@ +use cucumber::{gherkin::Step, given, then, when, World}; + +/// stores the current information for each scenario +#[derive(Debug, Default, World)] +struct NumWorld { + numbers: Vec<(f32, f32)>, +} + +/// is n about the same as m? +/// +/// This is actually not so easy! How do you measure *about same*ness? +/// Also, I don't think it is transitive, as 1 ≈ 1.1 ≈ 1.2 ≈ 1.3 ≈ ... ≈ 2 ≈ ... ≈ 3 ≈ ... ≈ infinity +#[inline] +fn about_same(n: f32, m: f32) -> bool { + (n - m).abs() <= calc_gate(n, m) +} + +#[inline] +fn calc_gate(n: f32, m: f32) -> f32 { + 0.01 + ((n.abs().sqrt().min(m.abs().sqrt())).abs() / 10f32) +} + +#[given(regex = r"the number n")] +async fn give_specific_number(world: &mut NumWorld, step: &Step) { + if let Some(table) = step.table.as_ref() { + for row in table.rows.iter() { + let n = row[0].parse::().unwrap(); + world.numbers.push((n, f32::NAN)); + } + } +} + +#[given("a number")] +async fn give_rand_number(world: &mut NumWorld) { + world.numbers.push(rand::random()); +} + +#[when("we calculate the inverted square root of it using the fast inverted square root algorithm")] +async fn calc_fast_inv_sqrt(world: &mut NumWorld) { + for pair in &mut world.numbers { + pair.1 = revsqrt::fast_inverse_sqrt(pair.0) + } +} + +#[when("we calculate the inverted square root of it normally")] +async fn calc_reg_inv_sqrt(world: &mut NumWorld) { + for pair in &mut world.numbers { + pair.1 = revsqrt::regular_inverse_sqrt(pair.0) + } +} + +#[then("the result can be calculated")] +async fn can_be_calculated(world: &mut NumWorld) { + for pair in &mut world.numbers { + assert!(!pair.0.is_nan()); + assert!(!pair.1.is_nan()); + assert!(pair.0.is_finite()); + assert!(pair.1.is_finite()); + } +} + +#[then("the result is about the same as if we calculate it normally")] +async fn comp_result_with_normal(world: &mut NumWorld) { + for pair in &mut world.numbers { + assert!(about_same(pair.1, revsqrt::regular_inverse_sqrt(pair.0))); + } +} + +#[then(regex = r"the result is m")] +async fn result_is(world: &mut NumWorld, step: &Step) { + if let Some(table) = step.table.as_ref() { + for (row, i) in std::iter::zip(table.rows.iter(), 0..table.rows.len() - 1) { + let m = row[0].parse::().unwrap(); + assert_eq!(world.numbers[i].1, m); + } + } +} + +#[tokio::main] +async fn main() { + NumWorld::run("tests/features/book/revsqrt-demo.feature").await; +}