#engineering #notation #numbers #configuration #human

engineering-repr

Numeric conversions for engineering notation (1.23k) and the RKM code variant (1k23)

4 releases (2 breaking)

new 0.3.1 Jan 7, 2025
0.3.0 Jan 4, 2025
0.2.0 Jan 2, 2025
0.1.0 Jan 1, 2025

#149 in Math

Download history 143/week @ 2024-12-27 261/week @ 2025-01-03

404 downloads per month
Used in qcp

MIT license

47KB
756 lines

Crates.io GitHub code size in bytes Build status Documentation License Coverage

Numeric conversions for engineering notation and RKM code.

Overview

In engineering applications it is common to express quantities relative to the next-lower power of 1000, described by an SI (metric) prefix.

This is normally done by writing the SI multiplier after the quantity. In the "RKM code" variant, the SI multiplier replaces the decimal point.

For example:

Number Engineering RKM
42 42 42
999 999 999
1000 1k 1k
1500 1.5k 1k5
42900 42.9k 42k9
2340000 2.34M 2M34

And so on going up the SI prefixes, including the new ones R (1027) and Q (1030) which were added in 2022.

This crate exists to support convenient conversion of numbers to/from engineering and RKM notation. The intended use case is reading user-entered strings from configuration files.

Detail

This crate is centred around the EngineeringQuantity<T> type.

  • The generic parameter T specifies the storage type to use for the significand. This can be any primitive integer except for i8 or u8.
    • For example, EngineeringQuantity<u64>.
  • The exponent is always stored as an i8.

You can convert an EngineeringQuantity to:

  • type T, or a larger integer type (one which implements From<T>)
  • String, optionally via the DisplayAdapter type for control over the output.
  • its component parts, as a tuple (<T>, i8) (see to_raw)
  • another EngineeringQuantity of a larger storage type (see convert; the new type must implement From<T>)

You can create an EngineeringQuantity from:

  • type T, or a smaller integer type (one which implements Into<T>)
  • String or &str, which autodetects both standard and RKM code variants
  • its component parts (<T>, i8) (see from_raw)
    • N.B. this applies an overflow check; it will fail if the number cannot fit into T.

Primitive types may be converted directly to string via the EngineeringRepr convenience trait.

Or, if you prefer, here are the type relations in diagram form:

    ╭─────────────────────╮    ╭─────────────────────╮    ╭───────────╮
    │      integers       │    │    integer types    │    │ raw tuple │
    │    (T or larger)    │    │    (T or smaller)   │    │  (T, i8)  │
    ╰─────────────────────╯    ╰─────────────────────╯    ╰───────────╯
      ╵          ▲                       │                 ▲         │
      ╵          │ From                  │ From            │ From    │ TryFrom
      ╵          │                       ▼                 │         ▼
      ╵       ┌───────────────────────────────────────────────────────────┐
      ╵       │              EngineeringQuantity<T>                       │
      ╵       └───────────────────────────────────────────────────────────┘
      ╵                                  │                 ▲          │
      ╵       ┌─────────────────────┐    │                 │          │
      ╵ impl  │   EngineeringRepr   │    │ (configurable   │ FromStr  │ Display
      └−−−−−▶ │ (convenience trait) │    │ format)         │          │
              └─────────────────────┘    │                 │          │
                │ to_eng(), to_rkm()     │                 │          │
                ▼                        │                 │          │
              ┌─────────────────────┐    │                 │          │
              │  DisplayAdapter<T>  │ ◀──┘                 │          │
              └─────────────────────┘                      │          │
                │ Display                                  │          │
                ▼                                          │          │
              ╭─────────────────────╮                      │          │
              │       String        │ ─────────────────────┘          │
              ╰─────────────────────╯ ◀───────────────────────────────┘

Examples

String to number

use engineering_repr::EngineeringQuantity as EQ;
use std::str::FromStr as _;

// Standard notation
let eq = EQ::<i64>::from_str("1.5k").unwrap();
assert_eq!(i64::try_from(eq).unwrap(), 1500);

// RKM style notation
let eq2 = EQ::<i64>::from_str("1k5").unwrap();
assert_eq!(eq, eq2);

Number to string

use engineering_repr::EngineeringQuantity as EQ;

// default precision (3 places)
let ee1 = EQ::<i32>::from(1200);
assert_eq!(ee1.to_string(), "1.20k");
// explicit precision
let ee2 = EQ::<i32>::from(1234567);
assert_eq!(ee2.with_precision(2).to_string(), "1.2M");

// RKM style
assert_eq!(ee2.rkm_with_precision(2).to_string(), "1M2");

// Zero precision means "automatic, lossless"
assert_eq!(ee2.with_precision(0).to_string(), "1.234567M");
assert_eq!(ee2.rkm_with_precision(0).to_string(), "1M234567");

Convenience trait

use engineering_repr::EngineeringRepr as _;
assert_eq!("123.45k", 123456.to_eng(5));
assert_eq!("123.456k", 123456.to_eng(0)); // automatic precision
assert_eq!("123k4", 123456.to_rkm(4));

Limitations

  • This crate only supports integers at the present time. The smaller multipliers (m, μ, n, p, f, a, z, y, r, q) are not currently supported.
  • Multipliers which are not a power of 1000 (da, h, d, c) are not supported.

Alternatives

  • human-repr is great for converting numbers to human-friendly representations.
  • humanize-rs is great for converting some human-friendly representations to numbers, though engineering-repr offers more flexibility.

Dependencies

~0.3–1MB
~20K SLoC