use super::*;
const SCIENCE: usize = 4;
fn write_normal_float<T: fmt::Write>(mut fm: T, a: f64, step: Option<f64>) -> fmt::Result {
if let Some(step) = step {
let k = (-step.log10()).ceil();
let k = k.max(0.0);
write!(fm, "{0:.1$}", a, k as usize)
} else {
write!(fm, "{0:e}", a)
}
}
fn write_science_float<T: fmt::Write>(mut fm: T, a: f64, step: Option<f64>) -> fmt::Result {
if let Some(step) = step {
let precision = if a == 0.0 {
0
} else {
let k1 = -step.log10().ceil();
let k2 = -a.abs().log10().ceil();
let k1 = k1 as isize;
let k2 = k2 as isize;
(k1 - k2).max(0) as usize
};
write!(fm, "{0:.1$e}", a, precision)
} else {
write!(fm, "{}", a)
}
}
pub fn write_interval_float<T: fmt::Write>(
mut fm: T,
a: f64,
step: Option<f64>,
) -> std::fmt::Result {
if a.abs().log10().floor().abs() > SCIENCE as f64 {
let mut k = String::new();
write_science_float(&mut k, a, step)?;
let mut j = String::new();
write_normal_float(&mut j, a, step)?;
let ans = if k.len() < j.len() { k } else { j };
write!(fm, "{}", ans)?;
} else {
write_normal_float(fm, a, step)?;
}
Ok(())
}
pub fn write_interval_i128<T: fmt::Write>(
mut fm: T,
a: i128,
step: Option<i128>,
) -> std::fmt::Result {
if (a.abs() as f64).log10().floor().abs() > SCIENCE as f64 {
let mut k = String::new();
write_science_float(&mut k, a as f64, step.map(|x| x as f64))?;
use std::fmt::Write;
let mut j = String::new();
write!(&mut j, "{}", a)?;
let ans = if k.len() < j.len() { k } else { j };
write!(fm, "{}", ans)?;
} else {
write!(fm, "{}", a)?;
}
Ok(())
}
pub(crate) fn disp_const<F: Fn(&mut fmt::Formatter) -> fmt::Result>(a: F) -> DisplayableClosure<F> {
DisplayableClosure::new(a)
}
pub(crate) struct DisplayableClosure<F>(pub F);
impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> DisplayableClosure<F> {
#[inline(always)]
pub fn new(a: F) -> Self {
DisplayableClosure(a)
}
}
impl<F: Fn(&mut fmt::Formatter) -> fmt::Result> fmt::Display for DisplayableClosure<F> {
#[inline(always)]
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
(self.0)(formatter)
}
}
pub fn range_iter(
range: [f64; 2],
num: usize,
) -> impl ExactSizeIterator<Item = f64> + Clone + Send + Sync + std::iter::FusedIterator {
assert!(range[1] > range[0]);
let [min, max] = range;
let diff = max - min;
let divf = num as f64;
(0..num).map(move |x| min + (x as f64 / divf) * diff)
}