Numbers

Big numbers

Integers and fractions of any size, exact: factorials, powers, gcd, modular powers, and fractions such as 1/3 + 1/6 = 1/2 with no rounding.

Version 1.0.0 · 5 functions · 4 crates

#maths#money#exact#fractions

Functions

What use bignum.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use bignum_calc, bignum_factorial from bignum (Quillo 0.6).

bignum_calc(a: str, op: str, b: str) → stror an error

Whole-number arithmetic on numbers given as text: op is "+", "-", "*", "/" (rounded toward minus infinity), "%" (never negative for a positive divisor), "^" (power), "gcd", "lcm", "cmp" (-1, 0 or 1). Results are text, exact, up to about 2.4 million digits; _, , and spaces in the input are ignored.

bignum_factorial(n: int) → anyor an error

n! exactly (n from 0 to 20,000), with its number of digits: { value, digits }.

bignum_pow_mod(base: str, exponent: str, modulus: str) → stror an error

base to the power exponent, modulo modulus, fast even for exponents with hundreds of digits: the step of RSA, Diffie-Hellman and primality tests.

fraction_calc(a: str, op: str, b: str) → stror an error

Exact fractions: a and b as "3/4", "-2", or "0.15" (read exactly as 3/20); op is "+", "-", "*", "/". The answer is in lowest terms, as "a/b" (or a whole number).

fraction_decimal(fraction: str, digits: int) → anyor an error

A fraction ("1/7") as a decimal with digits places (0 to 10,000), rounded half away from zero, and the fraction in lowest terms: { decimal, fraction }.

Get it

$ quillo install bignum               # bignum.qwer into this folder$ quillo install bignum --example     # and its example, bignum.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/bignum.qwer$ curl -O https://quillolang.org/plugins/files/bignum.qwe

Then, in your program, all of it or only what you call:

main.qwe
use bignum.qweruse bignum_calc, bignum_factorial from bignum      // Quillo 0.6: only these

It uses these crates, which cargo fetches the first time the plugin is built:

[dependencies]
num-bigint = "0.4"num-rational = "0.4"num-integer = "0.1"num-traits = "0.2"

Example

bignum.qwe
// Exact numbers for a maths quiz site and a money ledger: huge integers, and fractions that never round.////   quillo run bignum.qwe      then open http://localhost:8080/biguse "bignum.qwer"route GET /big = {    two_to_200: bignum_calc("2", "^", "200")?,    times: bignum_calc("123456789012345678901234567890", "*", "987654321098765432109876543210")?,    gcd: bignum_calc("1071", "gcd", "462")?,    hundred_factorial_digits: bignum_factorial(100)?.digits,    pow_mod: bignum_pow_mod("4", "13", "497")?,}// Splitting a bill three ways and adding the shares back up: exactly the bill again.route GET /split ? { total: str = "100.00" } {    let share = fraction_calc(total, "/", "3")?    { share, share_cents: fraction_decimal(share, 2)?.decimal, back: fraction_calc(fraction_calc(share, "+", share)?, "+", share)? }}route GET /fractions = { sum: fraction_calc("1/3", "+", "1/6")?, tenth: fraction_calc("0.1", "+", "0.2")?, seventh: fraction_decimal("1/7", 20)?.decimal }
$ quillo run bignum.qwe$ curl 'localhost:8080/big'$ curl 'localhost:8080/split'$ curl 'localhost:8080/fractions'

Source

bignum.qwer
//! Integers and fractions of any size, exact: factorials, powers, gcd and modular powers on numbers with thousands of digits, and fractions like 1/3 + 1/6 = 1/2 with no rounding. Numbers cross as text.//! version: 1.0.0//!//! [dependencies]//! num-bigint = "0.4"//! num-rational = "0.4"//! num-integer = "0.1"//! num-traits = "0.2"use num_bigint::BigInt;use num_integer::Integer;use num_rational::BigRational;use num_traits::{One, Signed, ToPrimitive, Zero};use serde_json::{json, Value};const MAX_DIGITS: usize = 200_000;const MAX_BITS: u64 = 8_000_000;fn int(s: &str) -> Result<BigInt, String> {    let t: String = s.trim().chars().filter(|c| *c != '_' && *c != ',' && *c != ' ').collect();    if t.len() > MAX_DIGITS {        return Err("a number is at most 200,000 digits here".into());    }    t.parse::<BigInt>().map_err(|_| format!("`{}` is not a whole number", s))}fn frac(s: &str) -> Result<BigRational, String> {    let t = s.trim();    if let Some((n, d)) = t.split_once('/') {        let d = int(d)?;        if d.is_zero() {            return Err(format!("`{}` divides by zero", s));        }        return Ok(BigRational::new(int(n)?, d));    }    if let Some((w, f)) = t.split_once('.') {        // A decimal is exact too: 0.1 is 1/10.        let neg = w.trim().starts_with('-');        let digits = f.trim();        if !digits.chars().all(|c| c.is_ascii_digit()) {            return Err(format!("`{}` is not a number", s));        }        let scale = BigInt::from(10).pow(digits.len() as u32);        let whole = int(if w.trim().is_empty() || w.trim() == "-" { "0" } else { w })?;        let part = if digits.is_empty() { BigInt::zero() } else { int(digits)? };        let n = whole.abs() * &scale + part;        return Ok(BigRational::new(if neg { -n } else { n }, scale));    }    Ok(BigRational::from_integer(int(t)?))}fn show(r: &BigRational) -> String {    if r.is_integer() { r.numer().to_string() } else { format!("{}/{}", r.numer(), r.denom()) }}/// Whole-number arithmetic on numbers given as text: `op` is "+", "-", "*", "/" (rounded toward minus infinity), "%" (never negative for a positive divisor), "^" (power), "gcd", "lcm", "cmp" (-1, 0 or 1)./// Results are text, exact, up to about 2.4 million digits; `_`, `,` and spaces in the input are ignored.pub fn bignum_calc(a: &str, op: &str, b: &str) -> Result<String, String> {    let (x, y) = (int(a)?, int(b)?);    Ok(match op.trim() {        "+" => (x + y).to_string(),        "-" => (x - y).to_string(),        "*" => (x * y).to_string(),        "/" | "%" if y.is_zero() => return Err("division by zero".into()),        "/" => x.div_floor(&y).to_string(),        "%" => x.mod_floor(&y).to_string(),        "^" => {            let e = y.to_u32().ok_or("the power is a whole number from 0 to 4 billion")?;            if x.bits().saturating_mul(e as u64) > MAX_BITS {                return Err("the result would have more than 2.4 million digits".into());            }            x.pow(e).to_string()        }        "gcd" => x.gcd(&y).to_string(),        "lcm" => x.lcm(&y).to_string(),        "cmp" => match x.cmp(&y) {            std::cmp::Ordering::Less => "-1".into(),            std::cmp::Ordering::Equal => "0".into(),            std::cmp::Ordering::Greater => "1".into(),        },        other => return Err(format!("`{}` is not an operation: + - * / % ^ gcd lcm cmp", other)),    })}/// n! exactly (n from 0 to 20,000), with its number of digits: `{ value, digits }`.pub fn bignum_factorial(n: i64) -> Result<Value, String> {    if !(0..=20_000).contains(&n) {        return Err("n is 0 to 20,000".into());    }    let mut f = BigInt::one();    for i in 2..=n {        f *= i;    }    let s = f.to_string();    Ok(json!({ "digits": s.len(), "value": s }))}/// `base` to the power `exponent`, modulo `modulus`, fast even for exponents with hundreds of digits: the step of RSA, Diffie-Hellman and primality tests.pub fn bignum_pow_mod(base: &str, exponent: &str, modulus: &str) -> Result<String, String> {    let (b, e, m) = (int(base)?, int(exponent)?, int(modulus)?);    if m.is_zero() || m.is_negative() {        return Err("the modulus is a whole number above 0".into());    }    if e.is_negative() {        return Err("the exponent is 0 or more".into());    }    Ok(b.modpow(&e, &m).to_string())}/// Exact fractions: `a` and `b` as "3/4", "-2", or "0.15" (read exactly as 3/20); `op` is "+", "-", "*", "/". The answer is in lowest terms, as "a/b" (or a whole number).pub fn fraction_calc(a: &str, op: &str, b: &str) -> Result<String, String> {    let (x, y) = (frac(a)?, frac(b)?);    let r = match op.trim() {        "+" => x + y,        "-" => x - y,        "*" => x * y,        "/" if y.is_zero() => return Err("division by zero".into()),        "/" => x / y,        other => return Err(format!("`{}` is not an operation: + - * /", other)),    };    Ok(show(&r))}/// A fraction ("1/7") as a decimal with `digits` places (0 to 10,000), rounded half away from zero, and the fraction in lowest terms: `{ decimal, fraction }`.pub fn fraction_decimal(fraction: &str, digits: i64) -> Result<Value, String> {    let r = frac(fraction)?;    let d = digits.clamp(0, 10_000) as u32;    let scale = BigInt::from(10).pow(d);    let scaled = r.clone() * BigRational::from_integer(scale.clone());    let rounded = scaled.round().to_integer();    let neg = rounded.is_negative();    let s = rounded.abs().to_string();    let s = if s.len() <= d as usize { format!("{}{}", "0".repeat(d as usize + 1 - s.len()), s) } else { s };    let (w, f) = s.split_at(s.len() - d as usize);    let dec = format!("{}{}{}", if neg { "-" } else { "" }, w, if d > 0 { format!(".{}", f) } else { String::new() });    Ok(json!({ "decimal": dec, "fraction": show(&r) }))}
Fractions fractions.qwer · 1.0.0Exact fractions for recipes, carpentry and school maths: "1 1/2", "3/8" and "12.5%" read and calculated without rounding, expressions worked out, decimals turned into simple fractions, measures rounded to 1/16 inch, and recipes scaled.fractionsmathscalculatorsexact7 views · 9 downloadsFinance finance.qwer · 1.0.0Loan payments and amortization tables, compound growth with deposits, net present value and internal rate of return, in cents.moneyloanscalculatorsmaths7 views · 6 downloadsClustering clustering.qwer · 1.0.0Data put into groups: k-means with k chosen by the elbow and silhouette, DBSCAN for groups of any shape and their outliers (in metres for latitude and longitude), and hierarchical clustering, on rows of numbers or maps.statisticsanalyticssegmentsgeomaths7 views · 7 downloadsFrequency spectrum fft.qwer · 1.0.0The frequency spectrum of samples from a microphone or sensor: frequencies and their strength, the dominant ones found between bins, and the signal's level.signalsaudiosensorsmaths8 views · 7 downloadsGraphs graph.qwer · 1.0.0Graphs given as edges: shortest paths with distances, task order by topological sort with cycles named, connected groups, and what a node reaches.graphsroutesdependenciesmaths7 views · 7 downloadsMatrices matrix.qwer · 1.0.0Matrices as lists of rows: linear systems solved, inverses, determinants, products and transposes, and least-squares fits such as a trend line.mathsstatisticslinear-algebraforecasting7 views · 8 downloads
Thread
87Useful? Like it, or add to its thread below.

Thread 0 posts

On Big numbers: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.