I can tell you exactly how many stars mp-units has. The number is right there on the GitHub
page and on my docs site, it updates in real time, and I can plot it against every competing
units library on a single chart. What I cannot tell you, even roughly, is how many people
actually use it.
A "1000 lm" LED lamp and a "1000 lm" low-pressure sodium lamp do not look equally bright at
night. The number on both boxes is a photopic value: it weights the lamp's spectrum with
\(V(\lambda)\), the spectral sensitivity of the eye's cone cells, which drive vision in
daylight. At night, rod cells take over, the sensitivity curve shifts towards blue
(\(V'(\lambda)\)), and the same two lamps deliver roughly 2000 and 250 scotopic lumens
respectively. Both figures are luminous fluxes. Both are expressed in lumens. And a program
that adds or compares them computes a result that is wrong by up to a factor of eight:
autoled=1000.*lm;// photopic value from the datasheetautosodium=250.*lm;// scotopic value from a night-visibility modelautototal=led+sodium;// compiles everywhere, means nothing
To the best of our knowledge, no units library catches this today, because every one of them
(including mp-units until now) models a lumen as a lumen. This post introduces
photometric conditions: a way to keep photopic, scotopic, mesopic, and custom quantities
in separate quantity hierarchies, so that the mistake above breaks at compile time, while
everything the physics does allow keeps working.
When you write constexpr double G = 6.674e-11; in your code, the type system makes a claim
that is not true. It claims the value is exact. It is not. The Newtonian constant of
gravitation is one of the least precisely known constants in physics. CODATA 2018 lists it
as 6.674 30(15) × 10⁻¹¹ m³ kg⁻¹ s⁻², and the (15) means the fifth significant digit is
already uncertain. Only four digits of G are actually known. Every result derived from
that double inherits an uncertainty that the program neither tracks nor reports. The code
happily prints ten significant digits of a solar mass computed from a constant that
guarantees four.
mp-units now models this honestly. This post introduces the uncertain<T> representation
type, the standard_uncertainty and relative_standard_uncertainty metadata for measured
constants, and the measurement_of helper that connects them.
Decibels are everywhere in engineering. Signal levels in dBm, sound pressure in
dB SPL, voltage gain in dB, filter slopes in dB/octave. The neper, pH, and stellar
magnitude share the same structure. Yet, to the best of our knowledge,
no general-purpose units library models logarithmic quantities correctly. Most do not
model them at all. The few that do treat a decibel as a non-linear scale or an offset
unit, and that choice gets the arithmetic wrong in ways that compile silently.
This article is a request for feedback. We believe we have a correct design, derived
from the same affine-space model we introduced for
absolute quantities. It also aims to stay consistent
with the ISO/IEC 80000 standards: especially IEC 80000-15:2026, Logarithmic quantities
and their units, which consolidates the logarithmic-quantity rules once held in ISO
80000-1:2009 (Annex C); together with ISO 80000-2 (the logarithm functions lb, ln,
lg), ISO 80000-8 (acoustics), and IEC 80000-13 (information theory). We have read those
against this design, cite them throughout, and call out the one place we knowingly diverge
from them (Open Question 5).
This post describes the design in full, from the quantity spec to the named units, the
arithmetic, the conversions, and every domain we surveyed (audio, RF, acoustics,
chemistry, astronomy, music, information theory). Then it lays out the
open questions, each with every alternative we
considered and our current preference. Before we implement any of this in mp-units, we
want the people who use these quantities daily to tell us where we are wrong.
High-Energy Physics software is routinely trusted with complex detector
geometries spanning millions of volumes, critical tracking and reconstruction
algorithms, and multi-day simulations running on the Grid. A single silent unit
mismatch in a double can invalidate an entire analysis or produce detector
geometry that is 10× the wrong size. This post shows how mp-units can bring
compile-time safety to HEP codebases (including a dedicated HEP system of
quantities and units) and how large projects like ATLAS can adopt it
incrementally without requiring a big-bang rewrite.
A few years ago at CppCon, an engineer who works with electrical power systems every day
stopped me after a talk. He told me that his team confuses active power, reactive
power, apparent power, and complex power all the time, and that the mistake is easy
to make and expensive to find. Then he said the sentence that has stuck with me since: a
units library that will not make those four incompatible types is of no use in his
industry.
He is right. And he is not alone.
Note: Revised on July 5, 2026 to incorporate the feedback in the comments below.
How do units and linear algebra fit together? We get that question often. The honest
answer is that two different questions hide inside it, and they have different solutions.
The occasion for answering now is concrete: mp-units ships opt-in integrations that let
mainstream linear algebra libraries (Eigen,
GLM, and Blaze)
act directly as the representation type of a quantity.
The Brno 2026 ISO C++ Committee meeting has just finished. It was the first
meeting of the C++29 cycle, and a surprising amount already landed in the working
draft. Below I share the highlights voted in during the closing plenary, followed
by an update on the quantities and units standardization effort.
Integers overflow. That is not a controversial statement. What is surprising
is how easily overflow can hide behind the abstraction of a units library.
Most developers immediately think of explicit or implicit scaling operations —
calling .in(unit) to convert a quantity, constructing a quantity from a different
unit, or assigning between quantities with different units. These are indeed
places where overflow can occur, and the library cannot prevent it at compile time
when the values are only known at runtime. But at least these operations are
visible in your code: you wrote the conversion, you asked for the scaling,
and you can reason about whether the multiplication or division might overflow
your integer type.
The far more insidious problem is what happens when you don't ask for a conversion.
When you write 1 * m + 1 * ft, the library must automatically convert both
operands to a common unit before performing the addition. That conversion —
which you never explicitly requested — involves multiplication or division by
scaling factors. With integer representations, those scaling operations can
overflow silently, producing garbage results that propagate through your
calculations undetected.
No compile-time programming can prevent this. The values are only known at
runtime. But very few libraries provide proper tools to detect it.
This article explains why that limitation is real, how other libraries have
tried to work around it, and what mp-units provides to close the gap as
tightly as the language allows.
Physical units libraries have always been very good at preventing dimensional
errors and unit mismatches. But there is a category of correctness that they have
universally ignored: domain constraints on quantity point values.
A latitude is not just a length divided by a radius. It is a value that lives in
\([-90°, +90°]\); anything outside that range is physically meaningless. An angle
used in bearing navigation wraps cyclically around a circle; treating it as an
unbounded real number ignores a fundamental property of the domain. A clinical
body-temperature sensor should reject a reading of \(44\ \mathrm{°C}\) at the API
boundary, not silently pass it downstream.
Type-level constraint enforcement for quantity points with this level of
flexibility is a relatively unexplored area in mainstream physical units libraries.
The approach we present here is novel and experimental — we are certain there are
edge cases and design considerations we haven't yet discovered.
This article describes the motivation in depth, the design we arrived at, and
the open questions we would love the community's help to answer.