use anyhow::{ensure, Context, Error};
use smallbigint::Uint;
use std::str::FromStr;
extern crate num_iter;
#[allow(dead_code)]
pub fn find_small_prime_factorization_str(
num: &str,
small_prime_limit: &str,
) -> Result<Option<Vec<String>>, Error> {
let n = Uint::from_str(num)
.context("when trying to parse first argument to find_small_prime_factorization_str")?;
let spl = Uint::from_str(small_prime_limit)
.context("when trying to parse second argument to find_small_prime_factorization_str")?;
ensure!(spl >= 20);
if let Some(factors) = find_small_prime_factorization(&n, &spl) {
let factors_str: Vec<String> = factors.into_iter().map(|x| format!("{}", x)).collect();
Ok(Some(factors_str))
} else {
Ok(None)
}
}
#[test]
fn find_small_prime_factorization_str_works() {
assert_eq!(
find_small_prime_factorization_str("12", "20")
.unwrap()
.unwrap(),
["2", "2", "3"]
)
}
fn find_small_prime_factorization(v: &Uint, small_prime_limit: &Uint) -> Option<Vec<Uint>> {
assert!(v >= 1);
let mut current = v.clone();
let mut factors: Vec<Uint> = Vec::new();
while current != 1 {
let (newfactor, new) = find_small_prime_factor(¤t, small_prime_limit)?;
factors.push(newfactor);
current = new;
}
Some(factors)
}
fn find_small_prime_factor(v: &Uint, small_prime_limit: &Uint) -> Option<(Uint, Uint)> {
if v % 2u8 == 0 {
return Some((Uint::small(2), v / 2u8));
}
let mut cur_factor = Uint::small(3);
while cur_factor < small_prime_limit {
if v % &cur_factor == 0 {
return Some((cur_factor.clone(), v / cur_factor));
}
cur_factor += 2u8;
}
None
}