formulas.rs
4.4 kB · rust · 134 lines
1use crate::Fault;2use mrlycore::json;3use mrlynum::formulas;4use mrlynum::series::EULER;5use std::f64::consts::{E, PI};6use wasm_bindgen::prelude::*;78const FLOOR: usize = 2;9const REACH: usize = 2000;10const STOPS: usize = 400;1112fn depth(n: usize) -> Result<usize, Fault> {13 if !(FLOOR..=REACH).contains(&n) {14 return Err(Fault::new(format!(15 "the depth must be between {FLOOR} and {REACH}."16 )));17 }18 Ok(n)19}2021fn drift(value: f64, limit: f64) -> f64 {22 (value - limit).abs() / limit.abs()23}2425fn reading(kind: &str, m: usize) -> Result<(f64, f64, f64), Fault> {26 let x = m as f64;27 Ok(match kind {28 "wallis" => {29 let v = formulas::wallis(m);30 (x, v, drift(v, PI / 2.0))31 }32 "leibniz" => {33 let v = formulas::leibniz(m);34 (x, v, drift(v, PI / 4.0))35 }36 "basel" => {37 let v = formulas::basel(m);38 (x, v, drift(v, PI * PI / 6.0))39 }40 "gamma" => {41 let v = formulas::euler_gamma_partial(m);42 (x, v, drift(v, EULER))43 }44 "e" => {45 let v = formulas::e_partial(m);46 (x, v, drift(v, E))47 }48 "primes" => {49 let v = formulas::prime_count(m) as f64;50 (x, v, drift(v, formulas::li(x)))51 }52 "goldbach" => {53 let v = formulas::goldbach(2 * m) as f64;54 (2.0 * x, v, 1.0 / v)55 }56 "mertens" => {57 let v = formulas::mertens(m) as f64;58 (x, v, v.abs() / x.sqrt())59 }60 _ => return Err(Fault::new(format!("no formula is named {kind:?}."))),61 })62}6364/// Reads the eight elementary systems at the depth n: the constants pi, e and gamma the crate holds, then each system's partial, its target, the gap and the gap against the target, with the prime count beside li and n over ln n, the Goldbach partition count of two n beside the smallest partition count of any even number up to it, and the Mertens sum beside the square root of n, as JSON.65#[wasm_bindgen]66pub fn formulas_read(n: usize) -> Result<String, Fault> {67 let n = depth(n)?;68 let card = |value: f64, limit: f64| {69 json!({70 "value": value,71 "limit": limit,72 "error": (value - limit).abs(),73 "rel": drift(value, limit),74 })75 };76 let count = formulas::prime_count(n);77 let li = formulas::li(n as f64);78 let record = formulas::goldbach_record(2 * n);79 let pairs = record.last().copied().unwrap_or(0);80 let least = record.iter().copied().min().unwrap_or(0);81 let sum = formulas::mertens(n);82 let root = (n as f64).sqrt();83 Ok(json!({84 "n": n,85 "constants": { "pi": PI, "e": E, "gamma": EULER },86 "cards": {87 "wallis": card(formulas::wallis(n), PI / 2.0),88 "leibniz": card(formulas::leibniz(n), PI / 4.0),89 "basel": card(formulas::basel(n), PI * PI / 6.0),90 "gamma": card(formulas::euler_gamma_partial(n), EULER),91 "e": card(formulas::e_partial(n), E),92 "primes": {93 "value": count,94 "li": li,95 "ratio": n as f64 / (n as f64).ln(),96 "gauge": count as f64 / li,97 "rel": drift(count as f64, li),98 },99 "goldbach": {100 "even": 2 * n,101 "value": pairs,102 "floor": least,103 "rel": 1.0 / pairs as f64,104 },105 "mertens": {106 "value": sum,107 "root": root,108 "rel": (sum as f64).abs() / root,109 },110 },111 })112 .to_string())113}114115/// Walks one of the eight systems from the floor up to n at the count of stops and returns each stop as its point on the number line, the partial there and the normalised gap it stands at, three numbers a stop, so the approach can be drawn.116#[wasm_bindgen]117pub fn formulas_walk(kind: &str, n: usize, stops: usize) -> Result<Vec<f64>, Fault> {118 let n = depth(n)?;119 if !(2..=STOPS).contains(&stops) {120 return Err(Fault::new(format!(121 "the stops must be between 2 and {STOPS}."122 )));123 }124 let stops = stops.min(n - FLOOR + 1).max(2);125 let mut out = Vec::with_capacity(stops * 3);126 for k in 0..stops {127 let at = FLOOR + (n - FLOOR) * k / (stops - 1);128 let (x, value, gauge) = reading(kind, at)?;129 out.push(x);130 out.push(value);131 out.push(gauge);132 }133 Ok(out)134}