foundry_common_fmt/exp.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
use alloy_primitives::{Sign, I256, U256};
use yansi::Paint;
/// Returns the number expressed as a string in exponential notation
/// with the given precision (number of significant figures),
/// optionally removing trailing zeros from the mantissa.
///
/// Examples:
///
/// ```text
/// precision = 4, trim_end_zeroes = false
/// 1234124124 -> 1.234e9
/// 10000000 -> 1.000e7
/// precision = 3, trim_end_zeroes = true
/// 1234124124 -> 1.23e9
/// 10000000 -> 1e7
/// ```
#[inline]
pub fn to_exp_notation(value: U256, precision: usize, trim_end_zeros: bool, sign: Sign) -> String {
let stringified = value.to_string();
let exponent = stringified.len() - 1;
let mut mantissa = stringified.chars().take(precision).collect::<String>();
// optionally remove trailing zeros
if trim_end_zeros {
mantissa = mantissa.trim_end_matches('0').to_string();
}
// Place a decimal point only if needed
// e.g. 1234 -> 1.234e3 (needed)
// 5 -> 5 (not needed)
if mantissa.len() > 1 {
mantissa.insert(1, '.');
}
format!("{sign}{mantissa}e{exponent}")
}
/// Formats a U256 number to string, adding an exponential notation _hint_ if it
/// is larger than `10_000`, with a precision of `4` figures, and trimming the
/// trailing zeros.
///
/// # Examples
///
/// ```
/// use alloy_primitives::U256;
/// use foundry_common_fmt::format_uint_exp as f;
///
/// # yansi::disable();
/// assert_eq!(f(U256::from(0)), "0");
/// assert_eq!(f(U256::from(1234)), "1234");
/// assert_eq!(f(U256::from(1234567890)), "1234567890 [1.234e9]");
/// assert_eq!(f(U256::from(1000000000000000000_u128)), "1000000000000000000 [1e18]");
/// assert_eq!(f(U256::from(10000000000000000000000_u128)), "10000000000000000000000 [1e22]");
/// ```
pub fn format_uint_exp(num: U256) -> String {
if num < U256::from(10_000) {
return num.to_string()
}
let exp = to_exp_notation(num, 4, true, Sign::Positive);
format!("{num} {}", format!("[{exp}]").dim())
}
/// Formats a U256 number to string, adding an exponential notation _hint_.
///
/// Same as [`format_uint_exp`].
///
/// # Examples
///
/// ```
/// use alloy_primitives::I256;
/// use foundry_common_fmt::format_int_exp as f;
///
/// # yansi::disable();
/// assert_eq!(f(I256::try_from(0).unwrap()), "0");
/// assert_eq!(f(I256::try_from(-1).unwrap()), "-1");
/// assert_eq!(f(I256::try_from(1234).unwrap()), "1234");
/// assert_eq!(f(I256::try_from(1234567890).unwrap()), "1234567890 [1.234e9]");
/// assert_eq!(f(I256::try_from(-1234567890).unwrap()), "-1234567890 [-1.234e9]");
/// assert_eq!(f(I256::try_from(1000000000000000000_u128).unwrap()), "1000000000000000000 [1e18]");
/// assert_eq!(
/// f(I256::try_from(10000000000000000000000_u128).unwrap()),
/// "10000000000000000000000 [1e22]"
/// );
/// assert_eq!(
/// f(I256::try_from(-10000000000000000000000_i128).unwrap()),
/// "-10000000000000000000000 [-1e22]"
/// );
/// ```
pub fn format_int_exp(num: I256) -> String {
let (sign, abs) = num.into_sign_and_abs();
if abs < U256::from(10_000) {
return format!("{sign}{abs}");
}
let exp = to_exp_notation(abs, 4, true, sign);
format!("{sign}{abs} {}", format!("[{exp}]").dim())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_to_exponential_notation() {
let value = 1234124124u64;
let formatted = to_exp_notation(U256::from(value), 4, false, Sign::Positive);
assert_eq!(formatted, "1.234e9");
let formatted = to_exp_notation(U256::from(value), 3, true, Sign::Positive);
assert_eq!(formatted, "1.23e9");
let value = 10000000u64;
let formatted = to_exp_notation(U256::from(value), 4, false, Sign::Positive);
assert_eq!(formatted, "1.000e7");
let formatted = to_exp_notation(U256::from(value), 3, true, Sign::Positive);
assert_eq!(formatted, "1e7");
}
}