Skip to content

Releases: nholthaus/units

v3.3.0

07 Jan 19:06
878b3b2

Choose a tag to compare

Corrected Semantics for Ratio-Dimensionless Units

This release fixes multiple inconsistencies in the handling of ratio-dimensionless units
(e.g. percent, ppm, ppb) that previously could lead to silent precision loss, unit-scale loss,
or incorrect results in compound expressions.

These changes primarily affect arithmetic involving:

  • integral-backed ratio-dimensionless units,
  • compound units such as ppb / yr,
  • accumulation over time or other dimensions.

1) Normalization and truncation behavior (fixed)

Previous behavior

Ratio-dimensionless units normalize to a fraction (e.g. 50% → 0.5), but that normalization could
happen in the unit’s underlying type. With integral underlying types, this could silently truncate.

Example:

percent<int>(50).value() == 0   // truncated from 0.5

This truncation could then propagate into arithmetic and comparisons.

Current behavior

Ratio-dimensionless units normalize in floating-point space when needed, so value() preserves the
fractional meaning regardless of underlying type:

percent<int>(50).value() == 0.5

2) Ratio scale could be lost in compound units (fixed)

Previous behavior

Expressions that form compound units from ratio-dimensionless numerators could discard the ratio
scale during type formation. For example, in:

ppb / yr

the result could behave as if it were effectively 1 / yr (dimensionally correct, numerically wrong).
This could surface when multiplying back by time:

(ppb_per_year * yr)  // could fail to round-trip to ppb semantics

Current behavior

Compound units preserve the ratio-dimensionless scale, so:

(ppb / yr) * yr  -> ppb

with the correct magnitude.


3) Mixed “points space” vs “fraction space” outcomes (fixed)

Ratio-dimensionless units have two relevant representations:

  • raw(): the stored “points” (e.g. 50_pct.raw() == 50)
  • value(): the normalized fraction (e.g. 50_pct.value() == 0.5)

Previous behavior

Semantically similar expressions could produce different results depending on which overloads were
selected (and thus whether raw() or value() was used internally).

Example class of issue:

dimensionless(1.0) / 50_pct    // not necessarily consistent with
1.0 / 50_pct

Current behavior

Scalar interactions with ratio-dimensionless units consistently use normalized values where a scalar
interpretation is intended, while unit-unit operations preserve ratio semantics until explicitly converted.

As a result, equivalent expressions remain equivalent in practice.


4) Compound assignment on ratio-dimensionless units is now defined

Previous behavior

Compound assignment operators (e.g. +=, *=, /=) could inherit the same inconsistencies described
above, especially for integral-backed ratio-dimensionless units.

Current behavior

Compound assignment behavior is explicitly defined so that:

  • arithmetic is performed in the correct semantic domain (normalized when appropriate),
  • the stored representation remains consistent and deterministic.

Summary of what changed for users

Before this release:

  • Integral-backed ratio-dimensionless values could silently change meaning due to truncation.
  • Compound unit formation could preserve dimensional correctness but lose numeric scale.
  • Equivalent expressions could yield different results based on operand ordering and overload selection.

After this release:

  • Ratio-dimensionless values are normalized consistently and without truncation.
  • Ratio scale is preserved through compound unit arithmetic (e.g. rates like ppb/yr).
  • Equivalent expressions are consistent in both type behavior and numeric results.

v3.2.0

18 Dec 15:48

Choose a tag to compare

Non-type template parameter (NTTP) support

v3.1.1

25 Sep 16:02

Choose a tag to compare

  • update gtest to 1.17.0 (mostly to make CMake happy)
  • update cmake support to 4.99
  • better cmake exports
  • add cpack for tar/deb/rpm

v2.3.5

25 Sep 16:04
8c6ff01

Choose a tag to compare

  • Fixes mil unit definition
  • Adds jerk units to cmake/documentation

v3.1.0-beta

21 Jan 15:42

Choose a tag to compare

v3.1.0-beta Pre-release
Pre-release

What's Changed

New Features:

  • Uplift to C++23
  • Alias template CTAD (meters length instead of meters<double> length)
  • ADL Improvements
  • SFINAE replaced by concepts where appropriate
  • NAN support
  • constexpr cmath functions
  • Many new units (jerk, radiometric units, etc)
  • unit constants (1.0 * km == kilometers(1.0))

Fixes:

  • ternary operator works as expected
  • cmake: Allow to use existing googletest package by @krf in #310
  • Fix compile error under GCC-12 by @krf in #309
  • MSVC-specific Empty Baseclass Optimization activation. by @Guillaume227 in #317
  • Fix mil definition by @ts826848 in #321
  • -Wshadow compilation warning fix - use -Wshadow for compiling tests by @Guillaume227 in #318
  • introduce UNIT_NO_LITERAL_SUPPORT directive by @Guillaume227 in #316

New Contributors

Full Changelog: v3.0.0.beta.2...v3.1.0-beta

v2.3.4

17 Dec 23:40

Choose a tag to compare

What's Changed

New Contributors

Full Changelog: v2.3.3...v2.3.4

v3.0.0 Beta 2

14 Oct 22:23

Choose a tag to compare

v3.0.0 Beta 2 Pre-release
Pre-release

What's Changed

  • Fix incorrect math function output for scaled dimensionless types, v3.x edition by @ts826848 in #295
  • fix locale unit test
  • update gtest cmake
  • add vs2019 to appveyor
  • make .value() and .to<>() behave the same for scaled dimensionless units
  • ensure consistency and testing of scaled dimensionless unit math functions

Full Changelog: v3.0.0.beta...v3.0.0.beta.2

v2.3.3

07 Oct 16:09
b04d436

Choose a tag to compare

Fixes mil definition

v3.0.0 Beta

26 Sep 19:15

Choose a tag to compare

v3.0.0 Beta Pre-release
Pre-release
  • added support for nlohmann json
  • NaN support
  • add Gal unit of acceleration
  • improved stream operators

v2.3.2

26 Sep 19:17
e75b56e

Choose a tag to compare

Various fixes and improvements