# scaler ## Introduction This crate provides a convenient `Formatter` to scale, round, and display numbers. Scaling describes the usage of [decimal / metric / SI unit prefixes](https://en.wikipedia.org/wiki/Metric_prefix) or [binary / IEC unit prefixes](https://en.wikipedia.org/wiki/Binary_prefix) to increase readability; though no scaling and scientific notation are also supported.\ Rounding can be done either to a specified magnitude or to a number of significant digits.\ Separators can be freely adjusted. The group separator separates groups of digits every 3 digits before the decimal separator, while the decimal separator separates the integer and fractional parts of a number.\ The sign behaviour can be set to only show the sign when the number is negative ("-"), which is the default, or always show the sign ("+" and "-"). The latter can be useful for highlighting differences. \ By default rounding can create trailing zeros. They can optionally be removed. ## Installation The feature `warn_about_problematic_separators` warns using `log::warn!` if separators are being set with `Formatter::set_separators` that could lead to ambiguous formatting. It depends on the [`log`](https://crates.io/crates/log) crate and is the only dependency. If a dependencyless build should be desired, it can be disabled by specifying `default-features = false` in your Cargo.toml entry. ## Usage 1. Execute `Formatter::new` to create a new `Formatter` with default settings. 1. Adjust separators, rounding, scaling, and sign behaviour as necessary using the setters. 1. Format numbers with `Formatter::format`. ### `Rounding` Examples have scaling disabled for easier understanding. - `Magnitude`: - Round to digit at magnitude $10^m$. - Contains $m$. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::Magnitude(-2)); assert_eq!(f.format(123.456), "123,46"); assert_eq!(f.format(0.789), "0,79"); assert_eq!(f.format(42069), "42.069,00"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::Magnitude(-1)); assert_eq!(f.format(123.456), "123,5"); assert_eq!(f.format(0.789), "0,8"); assert_eq!(f.format(42069), "42.069,0"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::Magnitude(0)); assert_eq!(f.format(123.456), "123"); assert_eq!(f.format(0.789), "1"); assert_eq!(f.format(42069), "42.069"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::Magnitude(1)); assert_eq!(f.format(123.456), "120"); assert_eq!(f.format(0.789), "0"); assert_eq!(f.format(42069), "42.070"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::Magnitude(2)); assert_eq!(f.format(123.456), "100"); assert_eq!(f.format(0.789), "0"); assert_eq!(f.format(42069), "42.100"); ``` - `SignificantDigits`: - Round to $n$ significant numbers. - Contains $n$. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::SignificantDigits(0)); assert_eq!(f.format(123.456), "0"); assert_eq!(f.format(0.789), "0"); assert_eq!(f.format(42069), "0"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::SignificantDigits(1)); assert_eq!(f.format(123.456), "100"); assert_eq!(f.format(0.789), "0,8"); assert_eq!(f.format(42069), "40.000"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::SignificantDigits(2)); assert_eq!(f.format(123.456), "120"); assert_eq!(f.format(0.789), "0,79"); assert_eq!(f.format(42069), "42.000"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::SignificantDigits(3)); assert_eq!(f.format(123.456), "123"); assert_eq!(f.format(0.789), "0,789"); assert_eq!(f.format(42069), "42.100"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::SignificantDigits(4)); assert_eq!(f.format(123.456), "123,5"); assert_eq!(f.format(0.789), "0,7890"); assert_eq!(f.format(42069), "42.070"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_rounding(scaler::Rounding::SignificantDigits(5)); assert_eq!(f.format(123.456), "123,46"); assert_eq!(f.format(0.789), "0,78900"); assert_eq!(f.format(42069), "42.069"); ``` ### `Scaling` - `Binary`: - Scales by factor $2^(10) = 1024$. - If no prefix for that magnitude defined: Fallback to scientific notation. - Contains whether or not to put space between number and unit prefix. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::Binary(true)); assert_eq!(f.format(0.5), "1,000 * 2^(-1)"); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(64), "64,00"); assert_eq!(f.format(128), "128,0"); assert_eq!(f.format(1023), "1.023"); assert_eq!(f.format(1024), "1,000 Ki"); assert_eq!(f.format(2_f64.powi(10)), "1,000 Ki"); assert_eq!(f.format(2_f64.powi(20)), "1,000 Mi"); assert_eq!(f.format(2_f64.powi(30)), "1,000 Gi"); assert_eq!(f.format(2_f64.powi(40)), "1,000 Ti"); assert_eq!(f.format(2_f64.powi(50)), "1,000 Pi"); assert_eq!(f.format(2_f64.powi(60)), "1,000 Ei"); assert_eq!(f.format(2_f64.powi(70)), "1,000 Zi"); assert_eq!(f.format(2_f64.powi(80)), "1,000 Yi"); assert_eq!(f.format(2_f64.powi(90)), "1,000 * 2^(90)"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::Binary(false)); assert_eq!(f.format(1024), "1,000Ki"); ``` - `Decimal`: - Scales by factor $10^(3) = 1000$. - If no prefix for that magnitude defined: Fallback to scientific notation. - Contains whether or not to put space between number and unit prefix. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::Decimal(true)); assert_eq!(f.format(1e-31), "1,000 * 10^(-31)"); assert_eq!(f.format(1e-30), "1,000 q"); assert_eq!(f.format(1e-27), "1,000 r"); assert_eq!(f.format(1e-24), "1,000 y"); assert_eq!(f.format(1e-21), "1,000 z"); assert_eq!(f.format(1e-18), "1,000 a"); assert_eq!(f.format(1e-15), "1,000 f"); assert_eq!(f.format(1e-12), "1,000 p"); assert_eq!(f.format(1e-9), "1,000 n"); assert_eq!(f.format(1e-6), "1,000 µ"); assert_eq!(f.format(1e-3), "1,000 m"); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(10), "10,00"); assert_eq!(f.format(100), "100,0"); assert_eq!(f.format(999), "999,0"); assert_eq!(f.format(1000), "1,000 k"); assert_eq!(f.format(1e3), "1,000 k"); assert_eq!(f.format(1e6), "1,000 M"); assert_eq!(f.format(1e9), "1,000 G"); assert_eq!(f.format(1e12), "1,000 T"); assert_eq!(f.format(1e15), "1,000 P"); assert_eq!(f.format(1e18), "1,000 E"); assert_eq!(f.format(1e21), "1,000 Z"); assert_eq!(f.format(1e24), "1,000 Y"); assert_eq!(f.format(1e27), "1,000 R"); assert_eq!(f.format(1e30), "1,000 Q"); assert_eq!(f.format(1e33), "1,000 * 10^(33)"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::Decimal(false)); assert_eq!(f.format(1000), "1,000k"); ``` - `None`: - no scaling - no fallback to scientific notation ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None); assert_eq!(f.format(1e-10), "0,0000000001000"); assert_eq!(f.format(0.1), "0,1000"); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(10), "10,00"); assert_eq!(f.format(100), "100,0"); assert_eq!(f.format(1000), "1.000"); assert_eq!(f.format(1e10), "10.000.000.000"); ``` - `Scientific`: - always scientific notation ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::Scientific); assert_eq!(f.format(0.1), "1,000 * 10^(-1)"); assert_eq!(f.format(1), "1,000 * 10^(0)"); assert_eq!(f.format(10), "1,000 * 10^(1)"); ``` ### Separators - `group_separator` - Separates groups every 3 digits before the decimal separator. - `decimal_separator` - Separates the integer and fractional parts of a number. Examples have scaling disabled for easier understanding. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_separators(".", ","); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(10), "10,00"); assert_eq!(f.format(100), "100,0"); assert_eq!(f.format(1000), "1.000"); assert_eq!(f.format(10000), "10.000"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_separators("", ","); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(10), "10,00"); assert_eq!(f.format(100), "100,0"); assert_eq!(f.format(1000), "1000"); assert_eq!(f.format(10000), "10000"); ``` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_scaling(scaler::Scaling::None) .set_separators(",", "."); assert_eq!(f.format(1), "1.000"); assert_eq!(f.format(10), "10.00"); assert_eq!(f.format(100), "100.0"); assert_eq!(f.format(1000), "1,000"); assert_eq!(f.format(10000), "10,000"); ``` ### `Sign` - `Always` - Always show sign, even when number is positive. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_sign(scaler::Sign::Always); assert_eq!(f.format(std::f64::NEG_INFINITY), "-∞"); assert_eq!(f.format(-1), "-1,000"); assert_eq!(f.format(0), "+0,000"); assert_eq!(f.format(1), "+1,000"); assert_eq!(f.format(std::f64::INFINITY), "+∞"); ``` - `OnlyMinus` - Only show sign when number is negative. ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_sign(scaler::Sign::OnlyMinus); assert_eq!(f.format(std::f64::NEG_INFINITY), "-∞"); assert_eq!(f.format(-1), "-1,000"); assert_eq!(f.format(0), "0,000"); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(std::f64::INFINITY), "∞"); ``` ### Trailing Zeros - `true` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_trailing_zeros(true); assert_eq!(f.format(1), "1,000"); assert_eq!(f.format(1.2), "1,200"); assert_eq!(f.format(1.23), "1,230"); assert_eq!(f.format(1.234), "1,234"); assert_eq!(f.format(1.2345), "1,234"); ``` - `false` ```Rust let f: scaler::Formatter = scaler::Formatter::new() .set_trailing_zeros(false); assert_eq!(f.format(1), "1"); assert_eq!(f.format(1.2), "1,2"); assert_eq!(f.format(1.23), "1,23"); assert_eq!(f.format(1.234), "1,234"); assert_eq!(f.format(1.2345), "1,234"); ```