moar cucumber knowledge
Cargo Check, Format, Fix and Test / cargo CI (push) Successful in 2m18s Details

This commit is contained in:
Christoph J. Scherr 2024-01-15 16:29:55 +01:00
parent b4006d7d90
commit 40a3db61ce
Signed by: cscherrNT
GPG Key ID: 8E2B45BC51A27EA7
2 changed files with 234 additions and 16 deletions

View File

@ -1,6 +1,122 @@
Feature: inverted square root feature Feature: inverted square root calculation
Scenario: If we calculate the inverted square root of a number using fast inverted square root, it's about the same as if we calculate it normally Scenario: Calculate fast inverted sqrt
Given a number Given a number
When We calculate the the inverted square root of a number using fast inverted square root 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 Then the result is about the same as if we calculate it normally
Scenario: Calculate regular inverted sqrt
Given a number
When we calculate the inverted square root of it normally
Then the result can be calculated
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 fast inverted sqrt with specific numbers
Given the number n
| n |
| 1 |
| 1.1 |
| 100 |
| 1337 |
| 123.45678900 |
| 1337.1337 |
When we calculate the inverted square root of it using the fast inverted square root algorithm
Then the result is about the same as m
| m |
| 1 |
| 0.9534625892455922 |
| 0.1 |
| 0.02734854943722097 |
| 0.0900000004095 |
| 0.027347182112297627 |
Scenario: Calculate regular inverted sqrt with specific numbers
Given the number n
| 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
| m |
| 1 |
| 0.9534625892455922 |
| 0.1 |
| 0.02734854943722097 |
| 0.0900000004095 |
| 0.027347182112297627 |
Scenario: Some numbers are about the same (0)
Given the number n
| n |
| 1 |
| 1.0001 |
| 0.999 |
| 0.9999999999 |
Then they are about the same
Scenario: Some numbers are about the same (1)
Given the number n
| n |
| 10 |
| 10.0001 |
| 9.997 |
| 10.025 |
Then they are about the same
Scenario: Some numbers are about the same (-3)
Given the number n
| n |
| -1000 |
| -1000.1 |
| -1001.1 |
Then they are about the same
Scenario: Some numbers are about the same (3)
Given the number n
| n |
| -1000 |
| -1000.1 |
| -1001.1 |
Then they are about the same
Scenario: Some numbers are about the same (7)
Given the number n
| n |
| 10000000 |
| 10000000 |
| 10000300 |
| 10000000.1 |
| 10000001.1 |
Then they are about the same
Scenario: Some numbers are not about the same (1)
Given the number n
| n |
| 2 |
| -2 |
| 0 |
| 20 |
| 20000 |
Then they are not about the same
Scenario: Some numbers are not about the same (7)
Given the number n
| n |
| 10000000 |
| 10001000 |
| 0 |
| 20000001.1 |
Then they are not about the same

View File

@ -1,31 +1,133 @@
use cucumber::{given, then, when, World}; use std::iter::zip;
use cucumber::{gherkin::Step, given, then, when, World};
use rand; use rand;
#[derive(Debug, Default, World)] #[derive(Debug, Default, World)]
pub struct NumWorld { pub struct NumWorld {
number: f32, numbers: Vec<(f32, f32)>,
result: f32,
} }
// is n about the same as m? // is n about the same as m?
// This is actually not so easy! How do you measure "about same"ness?
// Also, it is not transitive, as 1 ≈ 1.1 ≈ 1.2 ≈ 1.3 ≈ ... ≈ 2 ≈ ... ≈ 3 ≈ ... ≈ infinity, that's
// a thought of me at least?
#[inline]
fn about_same(n: f32, m: f32) -> bool { fn about_same(n: f32, m: f32) -> bool {
(n - m) * 1000f32 < 1f32 dbg!((n, m));
dbg!((n - m).abs());
dbg!(calc_gate(n, m));
dbg!((n - m).abs() < calc_gate(n, m));
(n - m).abs() <= calc_gate(n, m)
} }
// Steps are defined with `given`, `when` and `then` attributes. #[inline]
#[given(regex = r"^a number$")] fn calc_gate(n: f32, m: f32) -> f32 {
async fn hungry_cat(world: &mut NumWorld) { 0.01 + ((n.abs().sqrt().min(m.abs().sqrt())).abs() / 10f32)
world.number = rand::random();
} }
#[when("We calculate the the inverted square root of a number using fast inverted square root")] #[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().skip(1) {
// NOTE: skip header
let n = row[0].parse::<f32>().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) { async fn calc_fast_inv_sqrt(world: &mut NumWorld) {
world.result = revsqrt::fast_inverse_sqrt(world.number); for pair in &mut world.numbers {
pair.1 = revsqrt::fast_inverse_sqrt(pair.0)
}
} }
#[then("The result is about the same as if we calculate it normally")] #[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 is about the same as if we calculate it normally")]
async fn comp_result_with_normal(world: &mut NumWorld) { async fn comp_result_with_normal(world: &mut NumWorld) {
assert!(about_same(world.number, world.result)); for pair in &mut world.numbers {
assert!(about_same(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(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 zip(table.rows.iter().skip(1), 0..table.rows.len() - 1) {
// NOTE: skip header
let m = row[0].parse::<f32>().unwrap();
assert_eq!(world.numbers[i].1, m);
}
}
}
#[then(regex = r"the result is about the same as m")]
async fn result_is_about(world: &mut NumWorld, step: &Step) {
if let Some(table) = step.table.as_ref() {
for (row, i) in zip(table.rows.iter().skip(1), 0..table.rows.len() - 1) {
// NOTE: skip header
let m = row[0].parse::<f32>().unwrap();
assert!(
about_same(world.numbers[i].1, m),
"{} and {} are not about the same!",
world.numbers[i].1,
m
);
}
}
}
#[then("they are about the same")]
async fn they_are_about_the_same(world: &mut NumWorld) {
let mut still_same = true;
let mut last_num = world.numbers[0].0;
for tup in &world.numbers {
still_same &= about_same(tup.0, last_num);
assert!(
still_same,
"{} and {} are not about the same! (gate: {})",
tup.0, last_num, calc_gate(tup.0, last_num)
);
last_num = tup.0;
}
}
#[then("they are not about the same")]
async fn they_are_not_about_the_same(world: &mut NumWorld) {
let mut found_a_same = false;
let mut last_num = f32::NAN;
for tup in &world.numbers {
found_a_same |= about_same(tup.0, last_num);
assert!(
!found_a_same,
"{} and {} are about the same! (gate: {})",
tup.0, last_num, calc_gate(tup.0, last_num)
);
last_num = tup.0;
}
} }
#[tokio::main] #[tokio::main]