paper-half-interval-mobius.rs
2.8 kB · rust · 87 lines
1use figures::{ink, save, Board};2use mrlyrs::core::error::Result;3use std::f64::consts::PI;45const NAME: &str = "paper-half-interval-mobius";6const GAMMA: f64 = 0.577_215_664_901_532_9;7const LOW: f64 = 2.0;8const HIGH: f64 = 7.0;9const SAMPLES: usize = 1600;10const FIFTH: u64 = 94939;11const QUARTER: u64 = 3789;1213// CERTIFICATE1415fn rate(base: u64) -> f64 {16 let b = base as f64;17 let fill = (b + 1.0) / 2.0;18 let cp = 2f64.sqrt() - 4.0 / PI;19 let tan = (3.0 * PI / 8.0 + PI / (4.0 * b)).tan();20 let x0 = (b / PI) * ((b + 3.0).ln() + GAMMA + tan.ln()) + cp * (b + 1.0).powi(2) / (8.0 * b);21 (fill + x0 + 0.5 / (PI / (2.0 * b)).sin()) / fill22}2324fn margin(base: u64, bar: f64) -> f64 {25 bar - rate(base).ln() / (base as f64).ln()26}2728fn odd(x: f64) -> u64 {29 let n = x.round() as u64;30 if n % 2 == 1 {31 n32 } else {33 n + 134 }35}3637// FIGURE3839fn main() -> Result<()> {40 assert!(margin(FIFTH - 2, 0.2) < 0.0 && margin(FIFTH, 0.2) > 0.0);41 assert!(margin(QUARTER - 2, 0.25) < 0.0 && margin(QUARTER, 0.25) > 0.0);42 assert!((1.3678e-8..1.3679e-8).contains(&margin(FIFTH, 0.2)));43 assert!((7.9625e-6..7.9626e-6).contains(&margin(QUARTER, 0.25)));44 assert!((0.199_387_1..=0.199_387_2).contains(&(0.2 - margin(100_003, 0.2))));4546 let mut bases: Vec<u64> = (0..=SAMPLES)47 .map(|i| odd(10f64.powf(LOW + (HIGH - LOW) * i as f64 / SAMPLES as f64)))48 .collect();49 bases.extend([QUARTER - 2, QUARTER, FIFTH - 2, FIFTH]);50 bases.sort_unstable();51 bases.dedup();52 for &b in &bases {53 assert_eq!(margin(b, 0.2) > 0.0, b >= FIFTH);54 assert_eq!(margin(b, 0.25) > 0.0, b >= QUARTER);55 }5657 let mut board = Board::square();58 let frame = board.frame(0.08);59 let top = margin(*bases.last().unwrap(), 0.25);60 let bottom = margin(bases[0], 0.2);61 let pad = 0.04 * (top - bottom);62 let (hi, lo) = (top + pad, bottom - pad);63 let at = |b: u64, m: f64| {64 let u = ((b as f64).log10() - LOW) / (HIGH - LOW);65 (66 frame.x + frame.w * u,67 frame.y + frame.h * (hi - m) / (hi - lo),68 )69 };7071 for decade in 3..7 {72 let x = frame.x + frame.w * (decade as f64 - LOW) / (HIGH - LOW);73 board.segment((x, frame.y), (x, frame.y + frame.h), 1.4, ink::line());74 }75 let zero = at(bases[0], 0.0).1;76 board.segment((frame.x, zero), (frame.x + frame.w, zero), 2.2, ink::dim());7778 for (bar, wall, color) in [(0.25, QUARTER, ink::orange()), (0.2, FIFTH, ink::blue())] {79 let pts: Vec<(f64, f64)> = bases.iter().map(|&b| at(b, margin(b, bar))).collect();80 board.polyline(&pts, 5.0, color);81 let (x, y) = at(wall, 0.0);82 board.disc(x, y, 15.0, ink::ground());83 board.disc(x, y, 9.5, color);84 }85 save(NAME, &board)?;86 Ok(())87}