use super::helpers::impl_try_from;
#[allow(unused_imports)]
#[cfg(feature = "_float_f64")]
use crate::ExtFloat;
#[allow(unused_imports)]
#[cfg(feature = "alloc")]
use crate::{vec_ as vec, Vec};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub enum UnitSi {
Quetta,
Ronna,
Yotta,
Zetta,
Exa,
Peta,
Tera,
Giga,
Mega,
Kilo,
Hecto,
Deca,
#[default]
None,
Deci,
Centi,
Milli,
Micro,
Nano,
Pico,
Femto,
Atto,
Zepto,
Yocto,
Ronto,
Quecto,
}
#[allow(non_upper_case_globals)]
impl UnitSi {
pub const Q: Self = Self::Quetta;
pub const R: Self = Self::Ronna;
pub const Y: Self = Self::Yotta;
pub const Z: Self = Self::Zetta;
pub const E: Self = Self::Exa;
pub const P: Self = Self::Peta;
pub const T: Self = Self::Tera;
pub const G: Self = Self::Giga;
pub const M: Self = Self::Mega;
pub const k: Self = Self::Kilo;
pub const K: Self = Self::Kilo;
pub const h: Self = Self::Hecto;
pub const H: Self = Self::Hecto;
pub const da: Self = Self::Deca;
pub const D: Self = Self::Deca;
pub const d: Self = Self::Deci;
pub const c: Self = Self::Centi;
pub const m: Self = Self::Milli;
pub const u: Self = Self::Micro;
pub const n: Self = Self::Nano;
pub const p: Self = Self::Pico;
pub const f: Self = Self::Femto;
pub const a: Self = Self::Atto;
pub const z: Self = Self::Zepto;
pub const y: Self = Self::Yocto;
pub const r: Self = Self::Ronto;
pub const q: Self = Self::Quecto;
}
impl UnitSi {
#[must_use]
pub const fn symbol(&self) -> &str {
match self {
UnitSi::Quetta => "Q",
UnitSi::Ronna => "R",
UnitSi::Yotta => "Y",
UnitSi::Zetta => "Z",
UnitSi::Exa => "E",
UnitSi::Peta => "P",
UnitSi::Tera => "T",
UnitSi::Giga => "G",
UnitSi::Mega => "M",
UnitSi::Kilo => "k",
UnitSi::Hecto => "H",
UnitSi::Deca => "D",
UnitSi::None => "",
UnitSi::Deci => "d",
UnitSi::Centi => "c",
UnitSi::Milli => "m",
UnitSi::Micro => "µ",
UnitSi::Nano => "n",
UnitSi::Pico => "p",
UnitSi::Femto => "f",
UnitSi::Atto => "a",
UnitSi::Zepto => "z",
UnitSi::Yocto => "y",
UnitSi::Ronto => "r",
UnitSi::Quecto => "q",
}
}
#[must_use]
pub const fn symbol_ascii(&self) -> &str {
match self {
UnitSi::Micro => "u",
_ => self.symbol(),
}
}
#[must_use]
pub const fn name(&self) -> &str {
match self {
UnitSi::Quetta => "quetta",
UnitSi::Ronna => "ronna",
UnitSi::Yotta => "yotta",
UnitSi::Zetta => "zetta",
UnitSi::Exa => "exa",
UnitSi::Peta => "peta",
UnitSi::Tera => "tera",
UnitSi::Giga => "giga",
UnitSi::Mega => "mega",
UnitSi::Kilo => "kilo",
UnitSi::Hecto => "hecto",
UnitSi::Deca => "deca",
UnitSi::None => "",
UnitSi::Deci => "deci",
UnitSi::Centi => "centi",
UnitSi::Milli => "milli",
UnitSi::Micro => "micro",
UnitSi::Nano => "nano",
UnitSi::Pico => "pico",
UnitSi::Femto => "femto",
UnitSi::Atto => "atoo",
UnitSi::Zepto => "zepto",
UnitSi::Yocto => "yocto",
UnitSi::Ronto => "ronto",
UnitSi::Quecto => "quecto",
}
}
pub const BASE: i32 = 10;
pub const fn exp(&self) -> i32 {
match self {
UnitSi::Quetta => 30,
UnitSi::Ronna => 27,
UnitSi::Yotta => 24,
UnitSi::Zetta => 21,
UnitSi::Exa => 18,
UnitSi::Peta => 15,
UnitSi::Tera => 12,
UnitSi::Giga => 9,
UnitSi::Mega => 6,
UnitSi::Kilo => 3,
UnitSi::Hecto => 2,
UnitSi::Deca => 1,
UnitSi::None => 0,
UnitSi::Deci => -1,
UnitSi::Centi => -2,
UnitSi::Milli => -3,
UnitSi::Micro => -6,
UnitSi::Nano => -9,
UnitSi::Pico => -12,
UnitSi::Femto => -15,
UnitSi::Atto => -18,
UnitSi::Zepto => -21,
UnitSi::Yocto => -24,
UnitSi::Ronto => -27,
UnitSi::Quecto => -30,
}
}
pub const fn factor(&self) -> f64 {
match self {
UnitSi::Quetta => 1e30,
UnitSi::Ronna => 1e27,
UnitSi::Yotta => 1e24,
UnitSi::Zetta => 1e21,
UnitSi::Exa => 1e18,
UnitSi::Peta => 1e15,
UnitSi::Tera => 1e12,
UnitSi::Giga => 1e9,
UnitSi::Kilo => 1e3,
UnitSi::Mega => 1e6,
UnitSi::Hecto => 1e2,
UnitSi::Deca => 1e1,
UnitSi::None => 1e0,
UnitSi::Deci => 1e-1,
UnitSi::Centi => 1e-2,
UnitSi::Milli => 1e-3,
UnitSi::Micro => 1e-6,
UnitSi::Nano => 1e-9,
UnitSi::Pico => 1e-12,
UnitSi::Femto => 1e-15,
UnitSi::Atto => 1e-18,
UnitSi::Zepto => 1e-21,
UnitSi::Yocto => 1e-24,
UnitSi::Ronto => 1e-27,
UnitSi::Quecto => 1e-30,
}
}
pub const fn factor_i64(&self) -> i64 {
match self {
UnitSi::Exa => 1_000_000_000_000_000_000,
UnitSi::Peta => 1_000_000_000_000_000,
UnitSi::Tera => 1_000_000_000_000,
UnitSi::Giga => 1_000_000_000,
UnitSi::Mega => 1_000_000,
UnitSi::Kilo => 1_000,
UnitSi::Hecto => 100,
UnitSi::Deca => 10,
UnitSi::None => 1,
UnitSi::Deci => -10,
UnitSi::Centi => -100,
UnitSi::Milli => -1_000,
UnitSi::Micro => -1_000_000,
UnitSi::Nano => -1_000_000_000,
UnitSi::Pico => -1_000_000_000_000,
UnitSi::Femto => -1_000_000_000_000_000,
UnitSi::Atto => -1_000_000_000_000_000_000,
_ => todo![],
}
}
pub const fn factor_i128(&self) -> i128 {
match self {
UnitSi::Quetta => 1_000_000_000_000_000_000_000_000_000_000,
UnitSi::Ronna => 1_000_000_000_000_000_000_000_000_000,
UnitSi::Yotta => 1_000_000_000_000_000_000_000_000,
UnitSi::Zetta => 1_000_000_000_000_000_000_000,
UnitSi::Zepto => -1_000_000_000_000_000_000_000,
UnitSi::Yocto => -1_000_000_000_000_000_000_000_000,
UnitSi::Ronto => -1_000_000_000_000_000_000_000_000_000,
UnitSi::Quecto => -1_000_000_000_000_000_000_000_000_000_000,
_ => self.factor_i64() as i128,
}
}
#[must_use]
pub fn convert(value: f64, from: Self, to: Self) -> f64 {
if from == to {
return value;
}
let (from_factor, to_factor) = (from.factor(), to.factor());
value * (from_factor / to_factor)
}
#[must_use]
pub fn convert_i64(value: i64, from: Self, to: Self) -> (i64, i64) {
if from == to {
return (value, 0);
}
let (from_factor, to_factor) = (from.factor_i64(), to.factor_i64());
let converted = if from_factor > 0 && to_factor > 0 {
value * from_factor / to_factor
} else if from_factor > 0 && to_factor < 0 {
value * from_factor * to_factor.abs()
} else if from_factor < 0 && to_factor > 0 {
value * from_factor.abs() / to_factor
} else {
value * from_factor.abs() * to_factor.abs()
};
let remainder = if from_factor > 0 && to_factor > 0 {
value * from_factor % to_factor
} else if from_factor > 0 && to_factor < 0 {
value * from_factor
} else if from_factor < 0 && to_factor > 0 {
value % to_factor
} else {
0 };
(converted, remainder)
}
#[must_use]
pub fn convert_i128(value: i128, from: Self, to: Self) -> (i128, i128) {
if from == to {
return (value, 0);
}
let (from_factor, to_factor) = (from.factor_i128(), to.factor_i128());
let converted = if from_factor > 0 && to_factor > 0 {
value * from_factor / to_factor
} else if from_factor > 0 && to_factor < 0 {
value * from_factor * to_factor.abs()
} else if from_factor < 0 && to_factor > 0 {
value * from_factor.abs() / to_factor
} else {
value * from_factor.abs() * to_factor.abs()
};
let remainder = if from_factor > 0 && to_factor > 0 {
value * from_factor % to_factor
} else if from_factor > 0 && to_factor < 0 {
value * from_factor
} else if from_factor < 0 && to_factor > 0 {
value % to_factor
} else {
0 };
(converted, remainder)
}
#[cfg(any(feature = "std", feature = "_float_f64"))]
#[cfg_attr(feature = "nightly_doc", doc(cfg(any(feature = "std", feature = "_float_f64"))))]
pub fn reduce(value: f64) -> (f64, Self) {
match value.abs() {
value if value >= UnitSi::Quetta.factor() => {
(value / UnitSi::Quetta.factor(), UnitSi::Quetta)
}
value if value >= UnitSi::Ronna.factor() => {
(value / UnitSi::Ronna.factor(), UnitSi::Ronna)
}
value if value >= UnitSi::Yotta.factor() => {
(value / UnitSi::Yotta.factor(), UnitSi::Yotta)
}
value if value >= UnitSi::Zetta.factor() => {
(value / UnitSi::Zetta.factor(), UnitSi::Zetta)
}
value if value >= UnitSi::Exa.factor() => (value / UnitSi::Exa.factor(), UnitSi::Exa),
value if value >= UnitSi::Peta.factor() => {
(value / UnitSi::Peta.factor(), UnitSi::Peta)
}
value if value >= UnitSi::Tera.factor() => {
(value / UnitSi::Tera.factor(), UnitSi::Tera)
}
value if value >= UnitSi::Giga.factor() => {
(value / UnitSi::Giga.factor(), UnitSi::Giga)
}
value if value >= UnitSi::Mega.factor() => {
(value / UnitSi::Mega.factor(), UnitSi::Mega)
}
value if value >= UnitSi::Kilo.factor() => {
(value / UnitSi::Kilo.factor(), UnitSi::Kilo)
}
value if value >= UnitSi::Hecto.factor() => {
(value / UnitSi::Hecto.factor(), UnitSi::Hecto)
}
value if value >= UnitSi::Deca.factor() => {
(value / UnitSi::Deca.factor(), UnitSi::Deca)
}
value if value >= UnitSi::Deci.factor() => {
(value / UnitSi::Deci.factor(), UnitSi::Deci)
}
value if value >= UnitSi::Centi.factor() => {
(value / UnitSi::Centi.factor(), UnitSi::Centi)
}
value if value >= UnitSi::Milli.factor() => {
(value / UnitSi::Milli.factor(), UnitSi::Milli)
}
value if value >= UnitSi::Micro.factor() => {
(value / UnitSi::Micro.factor(), UnitSi::Micro)
}
value if value >= UnitSi::Nano.factor() => {
(value / UnitSi::Nano.factor(), UnitSi::Nano)
}
value if value >= UnitSi::Pico.factor() => {
(value / UnitSi::Pico.factor(), UnitSi::Pico)
}
value if value >= UnitSi::Femto.factor() => {
(value / UnitSi::Femto.factor(), UnitSi::Femto)
}
value if value >= UnitSi::Atto.factor() => {
(value / UnitSi::Atto.factor(), UnitSi::Atto)
}
value if value >= UnitSi::Zepto.factor() => {
(value / UnitSi::Zepto.factor(), UnitSi::Zepto)
}
value if value >= UnitSi::Yocto.factor() => {
(value / UnitSi::Yocto.factor(), UnitSi::Yocto)
}
value if value >= UnitSi::Ronto.factor() => {
(value / UnitSi::Ronto.factor(), UnitSi::Ronto)
}
value if value >= UnitSi::Quecto.factor() => {
(value / UnitSi::Quecto.factor(), UnitSi::Quecto)
}
_ => (value, UnitSi::None),
}
}
pub const fn reduce_i64(value: i64) -> (i64, Self, i64) {
match value {
value if value >= UnitSi::Exa.factor_i64() => {
(value / UnitSi::Exa.factor_i64(), UnitSi::Exa, value % UnitSi::Exa.factor_i64())
}
value if value >= UnitSi::Peta.factor_i64() => {
(value / UnitSi::Peta.factor_i64(), UnitSi::Peta, value % UnitSi::Peta.factor_i64())
}
value if value >= UnitSi::Tera.factor_i64() => {
(value / UnitSi::Tera.factor_i64(), UnitSi::Tera, value % UnitSi::Tera.factor_i64())
}
value if value >= UnitSi::Giga.factor_i64() => {
(value / UnitSi::Giga.factor_i64(), UnitSi::Giga, value % UnitSi::Giga.factor_i64())
}
value if value >= UnitSi::Mega.factor_i64() => {
(value / UnitSi::Mega.factor_i64(), UnitSi::Mega, value % UnitSi::Mega.factor_i64())
}
value if value >= UnitSi::Kilo.factor_i64() => {
(value / UnitSi::Kilo.factor_i64(), UnitSi::Kilo, value % UnitSi::Kilo.factor_i64())
}
value if value >= UnitSi::Hecto.factor_i64() => (
value / UnitSi::Hecto.factor_i64(),
UnitSi::Hecto,
value % UnitSi::Hecto.factor_i64(),
),
value if value >= UnitSi::Deca.factor_i64() => {
(value / UnitSi::Deca.factor_i64(), UnitSi::Deca, value % UnitSi::Deca.factor_i64())
}
value if value <= UnitSi::Atto.factor_i64() => {
(value * UnitSi::Atto.factor_i64().abs(), UnitSi::Atto, 0)
}
value if value <= UnitSi::Femto.factor_i64() => {
(value * UnitSi::Femto.factor_i64().abs(), UnitSi::Femto, 0)
}
value if value <= UnitSi::Pico.factor_i64() => {
(value * UnitSi::Pico.factor_i64().abs(), UnitSi::Pico, 0)
}
value if value <= UnitSi::Nano.factor_i64() => {
(value * UnitSi::Nano.factor_i64().abs(), UnitSi::Nano, 0)
}
value if value <= UnitSi::Micro.factor_i64() => {
(value * UnitSi::Micro.factor_i64().abs(), UnitSi::Micro, 0)
}
value if value <= UnitSi::Milli.factor_i64() => {
(value * UnitSi::Milli.factor_i64().abs(), UnitSi::Milli, 0)
}
value if value <= UnitSi::Centi.factor_i64() => {
(value * UnitSi::Centi.factor_i64().abs(), UnitSi::Centi, 0)
}
value if value <= UnitSi::Deci.factor_i64() => {
(value * UnitSi::Deci.factor_i64().abs(), UnitSi::Deci, 0)
}
_ => (value, UnitSi::None, 0),
}
}
pub const fn reduce_i128(value: i128) -> (i128, Self, i128) {
match value {
value if value >= UnitSi::Quetta.factor_i128() => (
value / UnitSi::Quetta.factor_i128(),
UnitSi::Quetta,
value % UnitSi::Quetta.factor_i128(),
),
value if value >= UnitSi::Ronna.factor_i128() => (
value / UnitSi::Ronna.factor_i128(),
UnitSi::Ronna,
value % UnitSi::Ronna.factor_i128(),
),
value if value >= UnitSi::Yotta.factor_i128() => (
value / UnitSi::Yotta.factor_i128(),
UnitSi::Yotta,
value % UnitSi::Yotta.factor_i128(),
),
value if value >= UnitSi::Zetta.factor_i128() => (
value / UnitSi::Zetta.factor_i128(),
UnitSi::Zetta,
value % UnitSi::Zetta.factor_i128(),
),
value if value <= UnitSi::Quecto.factor_i128() => {
(value * UnitSi::Quecto.factor_i128().abs(), UnitSi::Quecto, 0)
}
value if value <= UnitSi::Ronto.factor_i128() => {
(value * UnitSi::Ronto.factor_i128().abs(), UnitSi::Ronto, 0)
}
value if value <= UnitSi::Yocto.factor_i128() => {
(value * UnitSi::Yocto.factor_i128().abs(), UnitSi::Yocto, 0)
}
value if value <= UnitSi::Zepto.factor_i128() => {
(value * UnitSi::Zepto.factor_i128().abs(), UnitSi::Zepto, 0)
}
_ => {
let (v, p, r) = Self::reduce_i64(value as i64);
(v as i128, p, r as i128)
}
}
}
#[must_use]
#[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
#[cfg_attr(
feature = "nightly_doc",
doc(cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64"))))
)]
pub fn reduce_chain(value: f64, threshold: f64) -> Vec<(f64, Self)> {
if value == 0.0 {
return vec![(0.0, UnitSi::None)];
}
let mut result = Vec::new();
let mut remainder = value;
let effective_threshold =
if threshold <= 0.0 { crate::ExtFloatConst::MEDIUM_MARGIN } else { threshold };
while remainder.abs() > effective_threshold {
let (size, unit) = Self::reduce(remainder);
let integer_part = size.trunc();
let fractional_part = size - integer_part;
result.push((integer_part, unit));
remainder = fractional_part * unit.factor();
if remainder.abs() < effective_threshold {
break;
}
}
if remainder.abs() >= effective_threshold {
result.push((remainder, UnitSi::None));
}
result
}
#[must_use]
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
pub fn reduce_chain_i64(value: i64, threshold: i64) -> Vec<(i64, Self)> {
let mut result = Vec::new();
let mut remainder = value;
while remainder.abs() > threshold.abs() {
let (size, unit, new_remainder) = Self::reduce_i64(remainder);
result.push((size, unit));
remainder = new_remainder;
if remainder.abs() < threshold.abs() {
break;
}
}
if remainder.abs() >= threshold.abs() {
result.push((remainder, UnitSi::None));
}
result
}
#[must_use]
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
pub fn reduce_chain_i128(value: i128, threshold: i128) -> Vec<(i128, Self)> {
let mut result = Vec::new();
let mut remainder = value;
while remainder.abs() > threshold.abs() {
let (size, unit, new_remainder) = Self::reduce_i128(remainder);
result.push((size, unit));
remainder = new_remainder;
if remainder.abs() < threshold.abs() {
break;
}
}
if remainder.abs() >= threshold.abs() {
result.push((remainder, UnitSi::None));
}
result
}
}
impl UnitSi {
pub fn asc_iter() -> impl Iterator<Item = Self> {
const UNITS: [UnitSi; 25] = [
UnitSi::Quecto,
UnitSi::Ronto,
UnitSi::Yocto,
UnitSi::Zepto,
UnitSi::Atto,
UnitSi::Femto,
UnitSi::Pico,
UnitSi::Nano,
UnitSi::Micro,
UnitSi::Milli,
UnitSi::Centi,
UnitSi::Deci,
UnitSi::None,
UnitSi::Deca,
UnitSi::Hecto,
UnitSi::Kilo,
UnitSi::Mega,
UnitSi::Giga,
UnitSi::Tera,
UnitSi::Peta,
UnitSi::Exa,
UnitSi::Zetta,
UnitSi::Yotta,
UnitSi::Ronna,
UnitSi::Quetta,
];
UNITS.iter().copied()
}
pub fn desc_iter() -> impl Iterator<Item = Self> {
const UNITS: [UnitSi; 25] = [
UnitSi::Quetta,
UnitSi::Ronna,
UnitSi::Yotta,
UnitSi::Zetta,
UnitSi::Exa,
UnitSi::Peta,
UnitSi::Tera,
UnitSi::Giga,
UnitSi::Mega,
UnitSi::Kilo,
UnitSi::Hecto,
UnitSi::Deca,
UnitSi::None,
UnitSi::Deci,
UnitSi::Centi,
UnitSi::Milli,
UnitSi::Micro,
UnitSi::Nano,
UnitSi::Pico,
UnitSi::Femto,
UnitSi::Atto,
UnitSi::Zepto,
UnitSi::Yocto,
UnitSi::Ronto,
UnitSi::Quecto,
];
UNITS.iter().copied()
}
}
impl From<UnitSi> for f32 {
fn from(from: UnitSi) -> f32 {
from.factor() as f32
}
}
impl From<UnitSi> for f64 {
fn from(from: UnitSi) -> f64 {
from.factor()
}
}
impl From<UnitSi> for i64 {
fn from(from: UnitSi) -> i64 {
from.factor_i64()
}
}
impl From<UnitSi> for i128 {
fn from(from: UnitSi) -> i128 {
from.factor_i128()
}
}
impl_try_from![UnitSi, i64 => i32, i16, u64, u32, u16];
impl_try_from![UnitSi, i128 => u128];
#[cfg(test)]
mod tests {
#![allow(unused_imports)]
use super::{
UnitSi,
UnitSi::{
Centi, Deca, Deci, Giga, Hecto, Kilo, Mega, Micro, Milli, Nano, Quetta, Ronna, Tera,
Yotta, Zetta,
},
};
#[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
use crate::vec_ as vec;
use crate::{code::sf, num::ExtFloatConst};
#[test]
fn unit_si_reduce_i64() {
let value = 4 * i64::from(Tera);
let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
assert_eq!(reduced_value, 4);
assert_eq!(unit, Tera);
assert_eq!(remainder, 0);
let value = 15 * i64::from(Kilo) + 500; let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
assert_eq!(reduced_value, 15);
assert_eq!(unit, Kilo);
assert_eq!(remainder, 500);
let value = 1; let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
assert_eq!(reduced_value, 1);
assert_eq!(unit, UnitSi::None);
assert_eq!(remainder, 0);
let value = 999;
let (reduced_value, unit, remainder) = UnitSi::reduce_i64(value);
assert_eq!(reduced_value, 9);
assert_eq!(unit, Hecto);
assert_eq!(remainder, 99);
}
#[test]
fn unit_si_reduce_i128() {
let value = 3000 * i128::from(Ronna) + 5 * i128::from(Mega);
let (reduced_value, unit, remainder) = UnitSi::reduce_i128(value);
assert_eq!(reduced_value, 3);
assert_eq!(unit, Quetta);
assert_eq!(remainder, 5 * i128::from(Mega));
let value = 900_033; let (reduced_value, unit, remainder) = UnitSi::reduce_i128(value);
assert_eq!(reduced_value, 900);
assert_eq!(unit, Kilo);
assert_eq!(remainder, 33);
}
#[test]
#[cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64")))]
#[cfg_attr(
feature = "nightly_doc",
doc(cfg(any(feature = "std", all(feature = "alloc", feature = "_float_f64"))))
)]
fn unit_si_reduce_chain() {
let margin = f64::MEDIUM_MARGIN;
assert_eq![
UnitSi::reduce_chain(Giga.factor(), margin),
vec![(1.0, Giga)]
];
assert_eq![
UnitSi::reduce_chain(1.5 * Giga.factor(), margin),
vec![(1.0, Giga), (500.0, Mega)]
];
assert_eq![
UnitSi::reduce_chain(Giga.factor() + Kilo.factor(), margin),
sf! { vec![
(1.0, Giga), (9.0, Hecto), (9.0, Deca), (99.0, Deci),
(9.0, Centi), (9.0, Milli), (999.0, Micro), (917.0, Nano)
]}
];
assert_eq![
UnitSi::reduce_chain(Mega.factor() / 2.0, margin),
vec![(500.0, Kilo)]
];
assert_eq![
UnitSi::reduce_chain(Yotta.factor() + Zetta.factor() + Giga.factor(), margin),
sf! { vec![
(1.0, Yotta), (1.0, Zetta), (1.0, Giga), (88.0, Kilo), (9.0, Hecto),
(5.0, Deci), (8.0, Centi), (2.0, Milli), (341.0, Micro), (11.0, Nano)
]}
];
assert_eq![
UnitSi::reduce_chain(0.0, margin),
vec![(0.0, UnitSi::None)]
];
assert_eq![
UnitSi::reduce_chain(Giga.factor() / 2., margin),
vec![(500., Mega)]
];
}
}