Skip to content

Instantly share code, notes, and snippets.

@unfo
Created January 9, 2024 14:57
Show Gist options
  • Select an option

  • Save unfo/c504ee31dc2311cae6bdb973d4f5345c to your computer and use it in GitHub Desktop.

Select an option

Save unfo/c504ee31dc2311cae6bdb973d4f5345c to your computer and use it in GitHub Desktop.

Revisions

  1. unfo created this gist Jan 9, 2024.
    10 changes: 10 additions & 0 deletions Cargo.toml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    [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"
    68 changes: 68 additions & 0 deletions minimum_sample_size.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    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
    }
    }