|
quanta 0.1.0
Type-safe units for temperature, frequency, electrical and spatial quantities, modeled after std::chrono
|
Type-safe spatial units (length, area, volume), modeled after std::chrono::duration. Include <quanta/spatial>.
3_ft * 4_ft is exactly square_feet(12))250_mm, 8_mil, 6_ft, 12_nmi, 40_ac, 250_mL)std::format support** (when available), with opt-in power-form (24cm³), base-unit (0.000024m³) and scaled (1.5L) displaycount(), rep, period), so lengths plug into generic code such as frequency's wavelength()Every precision is an exact std::ratio of one meter, so metric and imperial quantities compare, add and convert exactly. Where a conversion is lossless it is implicit; otherwise it needs a cast, and floor, ceil, trunc and round give explicit rounding control:
Lengths expose the same count()/rep/period interface as std::chrono::duration, with period giving the precision in meters. That is what frequency's distance_like concept requires, so a spatial length can be the result type of a wavelength calculation (spatial itself does not depend on frequency). Areas and volumes have count() and rep but deliberately no period, so they are not mistaken for distances or durations:
All standard aliases use int64_t representation. The alias template length<Rep, Precision> covers custom representations and precisions, e.g. length<double> or length<float, std::milli>.
| Type | Unit | Precision |
|---|---|---|
nanometers | nm | 10⁻⁹ m |
micrometers | µm | 10⁻⁶ m |
millimeters | mm | 0.001 m |
centimeters | cm | 0.01 m |
meters | m | 1 m |
kilometers | km | 1,000 m |
mils | mil | 1/1000 in = 25.4 µm |
inches | in | 25.4 mm |
feet | ft | 12 in = 0.3048 m |
yards | yd | 3 ft = 0.9144 m |
miles | mi | 5280 ft = 1609.344 m |
nautical_miles | nmi | 1852 m |
Areas and volumes are quantities of square_meter_unit and cubic_meter_unit, with alias templates area<Rep, Precision> and volume<Rep, Precision> whose precision is a std::ratio of one square or cubic meter. They support the same arithmetic, conversions, rounding and comparisons as lengths, within their own unit.
| Type | Unit | Precision |
|---|---|---|
square_millimeters | mm² | 10⁻⁶ m² |
square_centimeters | cm² | 10⁻⁴ m² |
square_meters | m² | 1 m² |
hectares | ha | 1 hm² = 10,000 m² |
square_kilometers | km² | 10⁶ m² |
square_inches | in² | 645.16 mm² |
square_feet | ft² | 144 in² = 0.09290304 m² |
square_yards | yd² | 9 ft² = 0.83612736 m² |
acres | ac | 43,560 ft² = 4046.8564224 m² |
square_miles | mi² | 640 ac = 2,589,988.110336 m² |
| Type | Unit | Precision |
|---|---|---|
microliters (= cubic_millimeters) | µL | 1 mm³ = 10⁻⁹ m³ |
milliliters (= cubic_centimeters) | mL | 1 cm³ = 10⁻⁶ m³ |
liters | L | 1 dm³ = 10⁻³ m³ |
cubic_meters | m³ | 1 m³ |
cubic_inches | in³ | 16.387064 mL |
cubic_feet | ft³ | 1728 in³ = 28.316846592 L |
cubic_yards | yd³ | 27 ft³ = 0.764554857984 m³ |
us_gallons | gal | 231 in³ = 3.785411784 L |
Lengths, areas and volumes are related by these operators, and no others:
| Operation | Result |
|---|---|
| length × length | area |
| length × area, area × length | volume |
| area ÷ length | length |
| volume ÷ length | area |
| volume ÷ area | length |
Dividing two quantities of the same unit still yields a scalar (1_ac / 1_ft2 == 43560). Any other combination, such as area × area, length ÷ area or area + length, does not compile.
The result precision is the product (or quotient) of the operand precisions, and the representation is their common type, so products are exact:
Quotients divide the counts, so with integer representations they truncate in the result precision, which may be coarse when the operand precisions differ: square_meters(10) / millimeters(3) has kilometer precision and yields 3 km. Convert the operands first, or use floating-point representations, for fractional results.
A product whose precision cannot be represented as a std::ratio with intmax_t terms, such as nanometers × nanometers × nanometers (10⁻²⁷ m³), is a compile-time error.
| Area literal | Type | Volume literal | Type | |
|---|---|---|---|---|
50_mm2 | square_millimeters | 50_uL (also 50_µL, not on GCC < 14) | microliters | |
100_cm2 | square_centimeters | 50_mm3 | microliters (= cubic_millimeters) | |
12_m2 | square_meters | 250_mL | milliliters | |
3_ha | hectares | 250_cm3 | milliliters (= cubic_centimeters) | |
5_km2 | square_kilometers | 2_L | liters | |
144_in2 | square_inches | 3_m3 | cubic_meters | |
120_ft2 | square_feet | 231_in3 | cubic_inches | |
9_yd2 | square_yards | 10_ft3 | cubic_feet | |
40_ac | acres | 3_yd3 | cubic_yards | |
2_mi2 | square_miles | 5_gal | us_gallons |
Literals are integral and checked for overflow at compile time; use a floating-point type such as length<double> or volume<double, std::milli> for fractional values.
Following std::chrono semantics:
quantity_cast) are required when the conversion may lose precisionfloor, ceil, trunc and round provide explicit rounding controlBy default, to_string and std::format show a quantity in its own unit, whatever the format spec. {} renders the exact stored count with the precision's suffix: SI-prefixed meters for metric lengths (nm, µm, mm, cm, m, km) and mil, in, ft, yd, mi, nmi for the others. A non-empty spec such as {:.1f} changes only the number formatting: the count is rendered as a double with the spec and followed by the same suffix as {}. A different unit is shown only when you opt in with a unit marker (see below), or by converting the value first.
Areas and volumes have explicit suffixes rather than SI-prefixed ones (a millimeter squared is 10⁻⁶ m², not 10⁻³ m²). Some precisions also have a power form, which writes the precision as a power of a length unit:
| Precision | Default | Power form |
|---|---|---|
| 10⁻¹⁸, 10⁻¹², 10⁻⁶, 10⁻⁴, 1, 10⁶ m² | nm², µm², mm², cm², m², km² | same |
| 10⁴ m² | ha | hm² |
| mil², in², ft², yd², mi², nmi² | mil², in², ft², yd², mi², nmi² | same |
| acre | ac | ac |
| 10⁻¹⁸, 1, 10⁹ m³ | µm³, m³, km³ | same |
| 10⁻⁹ m³ | µL | mm³ |
| 10⁻⁶ m³ | mL | cm³ |
| 10⁻³ m³ | L | dm³ |
| in³, ft³, yd³, mi³, nmi³ | in³, ft³, yd³, mi³, nmi³ | same |
| US gallon | gal | gal |
Lengths have no separate power form.
A format spec may begin with one marker letter that opts into a different unit; the rest of the spec is then handled exactly as above. The same choices are available from to_string through tag arguments, which work with or without std::format support.
| Marker | to_string tag | Shows | Examples |
|---|---|---|---|
p | quanta::spatial::power_form | the exact count, with the power-form suffix | {:p} on 24_mL → 24cm³; {:p.1f} → 24.0cm³ |
b | quanta::spatial::base_unit | the value in the base unit: m, m² or m³ | {:b.1f} on 1500_mm → 1.5m; {:b} on 6_ft → 1.8288m; {:b} on 2_L → 0.002m³ |
s | quanta::spatial::scaled | metric values in a unit suited to their magnitude | {:s} on 1500_mm → 1.5m; {:s} on 1500_mL → 1.5L; {:s} on 6_ft → 6ft |
Wherever a floating-point value is rendered without a spec ({:b} and {:s} with nothing after the marker, {} and {:p} on floating-point quantities, and every to_string form), it is written in the shortest fixed notation that round-trips: never scientific, and without padding zeros (2.5, 1000000, 0.000024). to_string and std::format therefore produce exactly the same text: to_string(q, quanta::spatial::base_unit) matches {:b}, to_string(q, quanta::spatial::scaled) matches {:s}, and to_string(q) matches {}. An explicit spec such as {:b.3e} is applied as given.
The scaled form applies to metric precisions (those that are powers of ten of the base unit). It chooses the largest of these units in which the magnitude is at least 1, or the smallest if there is none, and shows zero and non-finite values (infinity, NaN) in the base unit:
nm, µm, mm, m, kmnm², µm², mm², m², km²µL, mL, L, m³Other precisions (mil, in, ft, yd, mi, nmi, their squares and cubes, acres and US gallons) are shown in their own unit, with the count as a double.
A spec that starts with p, b or s is always a marker, so these letters cannot be used as the fill character at the start of a spec: {:p>8.1f} is the marker followed by >8.1f, not right-alignment filled with p. Only one marker is allowed; a second one is passed on as part of the numeric spec and is a format error.
Precisions with no conventional suffix (such as the 0.2 mm common type of meters and inches, or the 10⁻³ m² area of meters × millimeters) are not formattable, with or without a marker; convert them to a named precision first.