abridgment/
lib.rs

1//! Abridgment
2
3use std::cmp::max;
4
5/// Abridge
6pub fn abridge<const DIGITS: usize>(value: f64, abridge: Abridging, rounding: Rounding) -> f64 {
7    let power = 10.0f64.powi(trailing_digits::<DIGITS>(value, abridge) as _);
8    round(value * power, rounding) / power
9}
10
11fn round(value: f64, rounding: Rounding) -> f64 {
12    match rounding {
13        // Returns the largest integer less than or equal to value.
14        Rounding::Floor => value.floor(),
15        // Returns the smallest integer greater than or equal to value.
16        Rounding::Ceil => value.ceil(),
17        // Returns the nearest integer to value. If a value is half-way between two integers, round away from 0.0.
18        Rounding::Round => value.round(),
19    }
20}
21
22fn trailing_digits<const DIGITS: usize>(value: f64, abridge: Abridging) -> usize {
23    let leading_digits = value.abs().log10().ceil();
24    match abridge {
25        // Treat fractions as negative leading digits so we have the correct total number of significant digits.
26        Abridging::Significant => max(0, DIGITS as isize - leading_digits as isize) as _,
27        Abridging::Mantissa => DIGITS,
28        // Negative logs become 0, never print more than 3 digits after the decimal.
29        Abridging::Total => DIGITS.saturating_sub(leading_digits as usize),
30    }
31}
32
33/// Abridging kind
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum Abridging {
36    /// Significant digits
37    Significant,
38    /// Mantissa digits
39    Mantissa,
40    /// Total digits
41    Total,
42}
43
44/// Rounding mode
45#[derive(Clone, Copy, Debug, PartialEq)]
46pub enum Rounding {
47    // Returns the largest integer less than or equal to value.
48    Floor,
49    // Returns the smallest integer greater than or equal to value.
50    Ceil,
51    // Returns the nearest integer to value. If a value is half-way between two integers, round away from 0.0.
52    Round,
53}
54
55pub mod prelude {
56    pub use crate::{
57        abridge,
58        Abridging::{Mantissa, Significant, Total},
59        Rounding::{Ceil, Floor, Round},
60    };
61}