formulas.rs

5.6 kB · rust · 208 lines

1use crate::classics::primes;2use crate::factor::mobius_sieve;3use crate::series::harmonic;45pub use crate::series::li;67// SIEVES89fn primal(limit: usize) -> Vec<bool> {10    let mut flag = vec![limit >= 2; limit + 1];11    for slot in flag.iter_mut().take(2.min(limit + 1)) {12        *slot = false;13    }14    let mut p = 2;15    while p * p <= limit {16        if flag[p] {17            let mut m = p * p;18            while m <= limit {19                flag[m] = false;20                m += p;21            }22        }23        p += 1;24    }25    flag26}2728fn pairs(flag: &[bool], number: usize) -> usize {29    (2..=number / 2)30        .filter(|&p| flag[p] && flag[number - p])31        .count()32}3334// CONSTANTS BY SUMMATION3536/// Returns the Wallis product taken to n paired factors, four k squared over four k squared less one, walking to pi over two.37///38/// ```39/// assert!((mrlynum::formulas::wallis(1) - 4.0 / 3.0).abs() < 1e-15);40/// ```41pub fn wallis(n: usize) -> f64 {42    let mut out = 1.0;43    for k in 1..=n {44        let square = ((2 * k) * (2 * k)) as f64;45        out *= square / (square - 1.0);46    }47    out48}4950/// Returns the Leibniz alternating sum of the odd reciprocals over n terms, walking to pi over four.51///52/// ```53/// assert!((mrlynum::formulas::leibniz(2) - 2.0 / 3.0).abs() < 1e-15);54/// ```55pub fn leibniz(n: usize) -> f64 {56    let mut out = 0.0;57    for k in 0..n {58        let term = 1.0 / (2 * k + 1) as f64;59        out += if k.is_multiple_of(2) { term } else { -term };60    }61    out62}6364/// Returns the Basel sum of the reciprocal squares over n terms, walking to pi squared over six.65///66/// ```67/// assert!((mrlynum::formulas::basel(3) - 49.0 / 36.0).abs() < 1e-15);68/// ```69pub fn basel(n: usize) -> f64 {70    (1..=n).map(|k| 1.0 / (k * k) as f64).sum()71}7273/// Returns the harmonic sum of n terms less the logarithm of n, walking to the Euler-Mascheroni constant.74///75/// ```76/// assert!((mrlynum::formulas::euler_gamma_partial(1) - 1.0).abs() < 1e-15);77/// ```78pub fn euler_gamma_partial(n: usize) -> f64 {79    if n == 0 {80        return 0.0;81    }82    harmonic(n) - (n as f64).ln()83}8485/// Returns one plus one over n raised to the n, walking to the natural base.86///87/// ```88/// assert!((mrlynum::formulas::e_partial(1) - 2.0).abs() < 1e-15);89/// ```90pub fn e_partial(n: usize) -> f64 {91    if n == 0 {92        return 1.0;93    }94    (1.0 + 1.0 / n as f64).powf(n as f64)95}9697// THE PRIMES COUNTED9899/// Returns the count of primes at or below n.100///101/// ```102/// assert_eq!(mrlynum::formulas::prime_count(100), 25);103/// ```104pub fn prime_count(n: usize) -> usize {105    primes(n).len()106}107108/// Returns the count of unordered pairs of primes summing to the number, zero below four.109///110/// ```111/// assert_eq!(mrlynum::formulas::goldbach(100), 6);112/// ```113pub fn goldbach(number: usize) -> usize {114    if number < 4 {115        return 0;116    }117    pairs(&primal(number), number)118}119120/// Returns the count of prime pairs at every even number from four up to the top, one entry per even number.121///122/// ```123/// assert_eq!(mrlynum::formulas::goldbach_record(10), vec![1, 1, 1, 2]);124/// ```125pub fn goldbach_record(top: usize) -> Vec<usize> {126    if top < 4 {127        return Vec::new();128    }129    let flag = primal(top);130    (2..=top / 2).map(|k| pairs(&flag, 2 * k)).collect()131}132133/// Returns the Mertens function at n, the Mobius values of one through n summed.134///135/// ```136/// assert_eq!(mrlynum::formulas::mertens(100), 1);137/// ```138pub fn mertens(n: usize) -> i64 {139    mobius_sieve(n).iter().skip(1).map(|&v| i64::from(v)).sum()140}141142#[cfg(test)]143mod tests {144    use super::*;145    use crate::prime::splits;146    use std::f64::consts::{E, PI};147148    #[test]149    fn the_small_partials_are_their_exact_fractions() {150        assert!((wallis(1) - 4.0 / 3.0).abs() < 1e-15);151        assert!((wallis(2) - 64.0 / 45.0).abs() < 1e-15);152        assert!((leibniz(1) - 1.0).abs() < 1e-15);153        assert!((leibniz(2) - 2.0 / 3.0).abs() < 1e-15);154        assert!((basel(3) - 49.0 / 36.0).abs() < 1e-15);155        assert!((euler_gamma_partial(1) - 1.0).abs() < 1e-15);156        assert!((e_partial(2) - 2.25).abs() < 1e-15);157    }158159    #[test]160    fn the_five_partials_walk_to_their_constants() {161        assert!((wallis(200_000) - PI / 2.0).abs() < 1e-5);162        assert!((leibniz(200_000) - PI / 4.0).abs() < 1e-5);163        assert!((basel(200_000) - PI * PI / 6.0).abs() < 1e-4);164        assert!((euler_gamma_partial(200_000) - crate::series::EULER).abs() < 1e-5);165        assert!((e_partial(200_000) - E).abs() < 1e-4);166    }167168    #[test]169    fn li_matches_its_own_series_at_two() {170        assert!((li(2.0) - 1.045_163_780_117_493).abs() < 1e-12);171    }172173    #[test]174    fn the_prime_count_is_the_sieve() {175        assert_eq!(prime_count(1), 0);176        assert_eq!(prime_count(100), 25);177        assert_eq!(prime_count(1000), 168);178        assert_eq!(prime_count(10_000), 1229);179    }180181    #[test]182    fn goldbach_counts_the_prime_pairs_the_long_way() {183        assert_eq!(goldbach(4), 1);184        assert_eq!(goldbach(100), 6);185        assert_eq!(goldbach(1000), 28);186        for even in (4..=600).step_by(2) {187            assert_eq!(goldbach(even), splits(even).len());188        }189    }190191    #[test]192    fn the_goldbach_record_never_reaches_zero_below_ten_thousand() {193        let record = goldbach_record(10_000);194        assert_eq!(record.len(), 4999);195        assert_eq!(record[0], 1);196        assert_eq!(record[498], 28);197        assert_eq!(record.iter().copied().min(), Some(1));198    }199200    #[test]201    fn mertens_sums_the_mobius_values() {202        assert_eq!(mertens(0), 0);203        assert_eq!(mertens(1), 1);204        assert_eq!(mertens(100), 1);205        assert_eq!(mertens(1000), 2);206        assert_eq!(mertens(10_000), -23);207    }208}