Dimensionless Quantities¶
The quantities we discussed so far always had some specific type and physical dimension. However, this is not always the case. While performing various computations, we sometimes end up with so-called "dimensionless" quantities, which ISO correctly defines as quantities of dimension one:
ISO/IEC Guide 99
- Quantity for which all the exponents of the factors corresponding to the base quantities in its quantity dimension are zero.
- The measurement units and values of quantities of dimension one are numbers, but such quantities convey more information than a number.
- Some quantities of dimension one are defined as the ratios of two quantities of the same kind.
- Numbers of entities are quantities of dimension one.
Dividing two quantities of the same kind¶
Dividing two quantities of the same kind always results in a quantity of dimension one. However, depending on what type of quantities we divide or what their units are, we may end up with slightly different results.
Note
In mp-units, dividing two quantities of the same dimension always results in a quantity
with the dimension being dimension_one
. This is often different for other physical units
libraries, which may return a raw representation type for such cases. A raw value is also always
returned from the division of two std::chrono::duration
objects.
To read more about the reasoning for this design decision, please check our FAQ.
Dividing quantities of the same type¶
First, let's analyze what happens if we divide two quantities of the same type:
In such a case, we end up with a dimensionless quantity that has the following properties:
static_assert(q.quantity_spec == dimensionless);
static_assert(q.dimension == dimension_one);
static_assert(q.unit == one);
In case we would like to print its value, we would see a raw value of 4
in the output with no unit
being printed.
Dividing quantities of different types¶
Now let's see what happens if we divide quantities of the same dimension and unit but which have different quantity types:
Again we end up with dimension_one
and one
, but this time:
As shown above, the result is not of a dimensionless
type anymore. Instead, we get a quantity type
derived from the performed quantity equation.
According to the ISQ, work divided by heat is the recipe for
the thermodynamic efficiency quantity, thus:
Note
The quantity of isq::efficiency_thermodynamics
is of a kind dimensionless
, so it is implicitly
convertible to dimensionless
and satisfies the QuantityOf<dimensionless>
concept.
Dividing quantities of different units¶
Now, let's see what happens when we divide two quantities of the same type but different units:
This time we still get a quantity of dimensionless
type with a dimension_one
as its dimension.
However, the resulting unit is not one
anymore:
In case we would print the text output of this quantity, we would not see a raw value of 2000
,
but 2 km/m
.
First, it may look surprising, but this is actually consistent with the division of quantities
of different dimensions. For example, if we divide 4 * km / 2 * s
, we do not expect km
to be
"expanded" to m
before the division, right? We would expect the result of 2 km/s
, which is
exactly what we get when we divide quantities of the same kind.
This is a compelling feature that allows us to express huge or tiny ratios without the need for big and expensive representation types. With this, we can easily define things like a Hubble's constant that uses a unit that is proportional to the ratio of kilometers per megaparsecs, which are both units of length:
inline constexpr struct hubble_constant :
named_unit<basic_symbol_text{"H₀", "H_0"}, mag<ratio{701, 10}> * si::kilo<si::metre> / si::second / si::mega<parsec>> {} hubble_constant;
Counts of things¶
Another important use case for dimensionless quantities is to provide strong types for counts of things. For example:
- ISO-80000-3 provides a
rotation
quantity defined as the number of revolutions, - IEC-80000-6 provides a
number_of_turns_in_a_winding
quantity, - IEC-80000-13 provides a
Hamming_distance
quantity defined as the number of digit positions in which the corresponding digits of two words of the same length are different.
Thanks to assigning strong names to such quantities, later on they can be explicitly used as arguments in the quantity equations of other quantities deriving from them.
Predefined units of the dimensionless quantity¶
As we observed above, the most common unit for dimensionless quantities is one
. It has the
ratio of 1
and does not output any textual symbol.
Important
A unit one
is special in the entire type system of units as it is considered to be
an identity operand in the unit expression templates.
This means that, for example:
static_assert(one * one == one);
static_assert(one * si::metre == si::metre);
static_assert(si::metre / si::metre == one);
The same is also true for dimension_one
and dimensionless
in the domains of dimensions
and quantity specifications.
Besides the unit one
, there are a few other scaled units predefined in the library for usage
with dimensionless quantities:
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
Angular quantities¶
Special, often controversial, examples of dimensionless quantities are an angular measure
and solid angular measure quantities that are defined in the ISQ
to be the result of a division of arc_length / radius
and area / pow<2>(radius)
respectively.
Moreover, ISQ also explicitly states that both can be
expressed in the unit one
. This means that both isq::angular_measure
and isq::solid_angular_measure
should be of a kind of dimensionless
.
On the other hand, ISQ also specifies that a unit radian
can
be used for isq::angular_measure
, and a unit steradian
can be used for isq::solid_angular_measure
.
Those should not be mixed or used to express other types of dimensionless quantities. This means
that both isq::angular_measure
and isq::solid_angular_measure
should also be
quantity kinds by themselves.
Note
Many people claim that angle being a dimensionless quantity is a bad idea. There are
proposals submitted to make an angle a base quantity and rad
to become a base unit. More on this
topic can be found in the "Strong Angular System" chapter.
Nested quantity kinds¶
Angular quantities are not the only ones with such a "strange" behavior. Another, but a similar case
is a storage_capacity
quantity specified in IEC-80000-13 that again allows expressing it in both
one
and bit
units.
Those cases make dimensionless quantities an exceptional tree in the library. This is the only quantity hierarchy that contains more than one quantity kind in its tree:
flowchart TD
dimensionless["dimensionless\n[one]"]
dimensionless --- rotation
dimensionless --- efficiency
dimensionless --- angular_measure["angular_measure\n[rad]"]
angular_measure --- rotational_displacement
angular_measure --- phase_angle
dimensionless --- solid_angular_measure["solid_angular_measure\n[sr]"]
dimensionless --- drag_factor
dimensionless --- storage_capacity["storage_capacity\n[bit]"] --- equivalent_binary_storage_capacity
dimensionless --- ...
To provide such support in the library, we provided an is_kind
specifier that can be appended
to the quantity specification:
inline constexpr struct angular_measure : quantity_spec<dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure : quantity_spec<dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity : quantity_spec<dimensionless, is_kind> {} storage_capacity;
inline constexpr struct angular_measure : quantity_spec<angular_measure, dimensionless, arc_length / radius, is_kind> {} angular_measure;
inline constexpr struct solid_angular_measure : quantity_spec<solid_angular_measure, dimensionless, area / pow<2>(radius), is_kind> {} solid_angular_measure;
inline constexpr struct storage_capacity : quantity_spec<storage_capacity, dimensionless, is_kind> {} storage_capacity;
With the above, we can constrain radian
, steradian
, and bit
to be allowed for usage with
specific quantity kinds only:
inline constexpr struct radian : named_unit<"rad", metre / metre, kind_of<isq::angular_measure>> {} radian;
inline constexpr struct steradian : named_unit<"sr", square(metre) / square(metre), kind_of<isq::solid_angular_measure>> {} steradian;
inline constexpr struct bit : named_unit<"bit", one, kind_of<storage_capacity>> {} bit;
but still allow a usage of one
and its scaled versions for such quantities.