Skip to content

Instantly share code, notes, and snippets.

@unfo
Created January 9, 2024 14:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unfo/c504ee31dc2311cae6bdb973d4f5345c to your computer and use it in GitHub Desktop.
Save unfo/c504ee31dc2311cae6bdb973d4f5345c to your computer and use it in GitHub Desktop.
[package]
name = "minimum_sample_size"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.4.14", features = ["derive"] }
num-integer = "0.1.45"
use clap::Parser;
use num_integer::Integer;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
// target precision we're after
#[arg(default_value_t = 1.0f64)]
target: f64,
#[arg(default_value_t = 0u32)]
repeating_decimals: u32
}
fn main() {
let args = Args::parse();
let precision: f64 = args.target;
let repeating: u32 = args.repeating_decimals;
match calculate_minimum_sample_size(precision, repeating) {
Some(size) => println!("Minimum number of people required: {}", size),
None => println!("Precision too fine to calculate with this method"),
}
}
fn calculate_minimum_sample_size(precision: f64, repeating_decimals: u32) -> Option<usize> {
if precision <= 0.0 || precision >= 1.0 {
return None;
}
let decimal_places = count_decimal_places(precision);
if repeating_decimals > 0 {
let power = repeating_decimals;
let denominator = 10usize.pow(power) - 1;
let multiplied = precision * 10f64.powi(power as i32);
let repeating_part = multiplied - multiplied.floor();
let mut repetition_added = multiplied;
for n in 0..repeating_decimals {
let f = (n + 1) as f64;
repetition_added += repeating_part * 10f64.powf(f * -1.0);
}
let subbed = repetition_added - precision;
let subbed_decimal = count_decimal_places(subbed);
let final_num = (subbed * 10f64.powi(subbed_decimal as i32)) as usize;
let final_den = denominator * 10usize.pow(subbed_decimal);
let gcd: usize = final_num.gcd(&final_den);
Some(final_den / gcd)
} else {
let power = decimal_places;
let denominator = 10usize.pow(power);
let multiplied = (precision * 10f64.powi(power as i32)) as usize;
let gcd = multiplied.gcd(&denominator);
Some(denominator / gcd)
}
}
fn count_decimal_places(input: f64) -> u32 {
let input_str = input.to_string();
let parts: Vec<&str> = input_str.split('.').collect();
if parts.len() == 2 {
parts[1].trim_end_matches('0').len() as u32
} else {
0
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment