1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
use crate::util;
use std::sync::mpsc;
use std::thread;

pub fn pihex(d: u64) -> String {
    let (tx, rx) = mpsc::channel();
    for &(j, k, l) in &[
        (4, 1, -32.0),
        (4, 3, -1.0),
        (10, 1, 256.0),
        (10, 3, -64.0),
        (10, 5, -4.0),
        (10, 7, -4.0),
        (10, 9, 1.0),
    ] {
        let tx = tx.clone();
        thread::spawn(move || tx.send(l * series_sum(d, j, k)).unwrap());
    }
    drop(tx);
    let fraction: f64 = rx.iter().sum();
    (0..4)
        .scan(fraction, |x, _| {
            *x = (*x - x.floor()) * 16.0;
            Some(format!("{:x}", x.floor() as u32))
        })
        .fold(String::new(), |s, t| s + &t)
}

fn series_sum(d: u64, j: u64, k: u64) -> f64 {
    let fraction1: f64 = (0..(2 * d + 2) / 5)
        .map(|i| {
            (if i % 2 == 0 { 1.0 } else { -1.0 })
                * util::pow_mod(4, 2 * d - 3 - 5 * i, j * i + k) as f64
                / (j * i + k) as f64
        })
        .fold(0.0, |x, y| (x + y).fract());
    let fraction2: f64 = ((2 * d + 2) / 5..)
        .map(|i| -(-4.0_f64).powi(-((5 * i + 3 - 2 * d) as i32)) / ((j * i + k) as f64))
        .take_while(|&x| x.abs() > 1e-13_f64)
        .sum();
    fraction1 + fraction2
}