├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "continued-fraction" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "continued-fraction" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | continued fraction cli implemented in rust 3 | 4 | each command looks like this: 5 | 6 | ` [mode]` 7 | 8 | modes: 9 | - f|frac|fraction: show just the answer (default); 10 | - c|conv|convergents|cf: show the answer and the convergents used in the algorithm. 11 | 12 | ``` 13 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io::{stdin, stdout, Write}; 2 | 3 | fn main() { 4 | loop { 5 | print!("> "); 6 | stdout().flush().ok(); 7 | 8 | let mut input = String::new(); 9 | if let Err(err) = stdin().read_line(&mut input) { 10 | eprintln!("{err}"); 11 | continue; 12 | } 13 | 14 | let (num, mode) = match input.trim().split_whitespace().collect::>()[..] { 15 | [num, mode] => (num, mode), 16 | [num] => (num, ""), 17 | _ => ("", ""), 18 | }; 19 | 20 | match num.parse::() { 21 | Ok(num) => { 22 | let fraction = continued_fraction(num) 23 | .take_while(|x| *x < 100) 24 | .take(16) 25 | .collect::>(); 26 | let (p, q) = find_convergents(&fraction); 27 | match mode { 28 | "" | "f" | "fr" | "fraction" => { 29 | println!("{p}/{q}"); 30 | } 31 | "c" | "conv" | "convergents" | "cf" => { 32 | println!("{p}/{q}"); 33 | println!("{fraction:?}"); 34 | } 35 | _ => eprintln!("unknown mode: '{mode}'"), 36 | } 37 | } 38 | Err(err) => { 39 | eprintln!("{err}"); 40 | continue; 41 | } 42 | }; 43 | } 44 | } 45 | 46 | fn continued_fraction(mut n: f64) -> impl Iterator { 47 | std::iter::from_fn(move || { 48 | let i = n.floor(); 49 | let f = n - i; 50 | n = 1.0 / f; 51 | Some(i as u64) 52 | }) 53 | } 54 | 55 | fn find_convergents(vec: &[u64]) -> (u64, u64) { 56 | fn p_n(vec: &[u64]) -> u64 { 57 | let len = vec.len(); 58 | match vec { 59 | [] => 1, 60 | [x] => *x, 61 | [.., x] => x * p_n(&vec[..(len - 1)]) + p_n(&vec[..(len - 2)]), 62 | } 63 | } 64 | fn q_n(vec: &[u64]) -> u64 { 65 | let len = vec.len(); 66 | match vec { 67 | [] => 0, 68 | [_] => 1, 69 | [.., x] => x * q_n(&vec[..(len - 1)]) + q_n(&vec[..(len - 2)]), 70 | } 71 | } 72 | (p_n(vec), q_n(vec)) 73 | } 74 | --------------------------------------------------------------------------------