use std::fmt::Write;
use r2rs_nmath::traits::DPQ;
pub fn stem_leaf_plot(x: &[f64]) -> String {
let atom = 1e-8;
let scale = 1.0;
let width = 80;
let mut x = x
.iter()
.filter(|x| x.is_finite())
.cloned()
.collect::<Vec<_>>();
x.sort_by(|x1, x2| x1.partial_cmp(x2).unwrap());
let n = x.len();
let mut mu = 10;
let r;
let mut c;
if x[n - 1] > x[0] {
r = atom + (x[n - 1] - x[0]) / scale;
c = 10.0_f64.pow_di((1.0 - r.log10().floor()) as isize);
let mm = 0.max((r * c / 25.0) as isize).min(2);
let k = 3 * mm + 2 - 150 / (n as isize + 50);
if (k - 1) * (k - 2) * (k - 5) == 0 {
c *= 10.;
}
let mut x1 = x[0].abs();
let x2 = x[n - 1].abs();
if x2 > x1 {
x1 = x2;
}
while x1 * c > usize::MAX as f64 {
c /= 10.0;
}
if k * (k - 4) * (k - 8) == 0 {
mu = 5;
}
if (k - 1) * (k - 5) * (k - 6) == 0 {
mu = 20;
}
} else {
r = atom + x[0].abs() / scale;
c = 10.0_f64.pow_di((1.0 - r.log10().floor()) as isize);
}
let mut lo = (x[0] * c / mu as f64).floor() as isize * mu;
let mut hi = (x[n - 1] * c / mu as f64).floor() as isize * mu;
let ldigits = if lo < 0 {
(-lo as f64).log10().floor() as usize + 1
} else {
0
};
let hdigits = if hi > 0 {
(hi as f64).log10().floor() as usize
} else {
0
};
let ndigits = if ldigits < hdigits { hdigits } else { ldigits };
if lo < 0 && (x[0] * c).floor() as isize == lo {
lo = lo - mu;
}
hi = lo + mu;
if (x[0] * c + 0.5).floor() as isize > hi {
lo = hi;
hi = lo + mu;
}
let mut ret = String::new();
let pdigits = 1 - (c.log10() + 0.5).floor() as isize;
if pdigits == 0 {
writeln!(ret, "The decimal point is at the |\n").unwrap();
} else {
writeln!(
ret,
"The decimal point is {} digit(s) to the {} of the |\n",
pdigits.abs(),
if pdigits > 0 { "right" } else { "left" }
)
.unwrap();
}
let stem_print = |ret: &mut String, close: isize, dist: isize, ndigits: usize| {
if close / 10 == 0 && dist < 0 {
write!(ret, "{:width$} | ", "-0", width = ndigits).unwrap();
} else {
write!(ret, "{:width$} | ", close / 10, width = ndigits).unwrap();
}
};
let mut i = 0;
loop {
if lo < 0 {
stem_print(&mut ret, hi, lo, ndigits);
} else {
stem_print(&mut ret, lo, hi, ndigits);
}
let mut j = 0;
loop {
let xi = if x[i] < 0.0 {
(x[i] * c - 0.5) as isize
} else {
(x[i] * c + 0.5) as isize
};
if (hi == 0 && x[i] >= 0.0) || (lo < 0 && xi > hi) || (lo >= 0 && xi >= hi) {
break;
}
j += 1;
if j <= width - 12 {
write!(ret, "{}", xi.abs() % 10).unwrap();
}
i += 1;
if !(i < n) {
break;
}
}
if j > width {
write!(ret, "+{}", j - width).unwrap();
}
writeln!(ret).unwrap();
if i >= n {
break;
}
hi += mu;
lo += mu;
}
ret
}