From 1b5b4dbdcd0afcd39dd1957f6f56020e1bbfbe77 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 26 Dec 2023 11:07:21 +0100 Subject: [PATCH] docs: "Framework Basics" chapters updated and cleaned up --- CHANGELOG.md | 3 +- .../character_of_a_quantity.md | 58 ++++++------ .../dimensionless_quantities.md | 44 ++++----- .../faster_than_lightspeed_constants.md | 12 +-- .../framework_basics/generic_interfaces.md | 90 +++++++++++++------ .../framework_basics/quantity_arithmetics.md | 61 +++++++------ .../simple_and_typed_quantities.md | 10 +-- .../framework_basics/value_conversions.md | 10 +-- 8 files changed, 160 insertions(+), 128 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 092d49497..f7ba2a08c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### 2.2.0 WIP { id="2.2.0" } -- feat: `fma`, `isfinite`, `isinf`, and `isnan` math function added by @NAThompson +- feat: `fma`, `isfinite`, `isinf`, and `isnan` math function added by [@NAThompson](https://github.com/NAThompson) - feat: `quantity_point` support added for `quantity_cast` and `value_cast` - feat: `value_cast` added - (!) refactor: `zero_Fahrenheit` renamed to `zeroth_degree_Fahrenheit` @@ -15,6 +15,7 @@ - docs: project blog and first posts added - docs: project documentation layout refactored - docs: "Interoperability with Other Libraries" chapter added +- docs: "Framework Basics" chapters updated and cleaned up ### 2.1.0 December 9, 2023 { id="2.1.0" } diff --git a/docs/users_guide/framework_basics/character_of_a_quantity.md b/docs/users_guide/framework_basics/character_of_a_quantity.md index 3cf182696..ad3660780 100644 --- a/docs/users_guide/framework_basics/character_of_a_quantity.md +++ b/docs/users_guide/framework_basics/character_of_a_quantity.md @@ -18,8 +18,8 @@ Such distinction is important because each quantity character represents different properties and allows different operations to be done on its quantities. -For example, imagine a physical units library that allows the creation of a `speed` quantity from both -`length / time` and `length * time`. It wouldn't be too safe to use such a product, right? +For example, imagine a physical units library that allows the creation of a $speed$ quantity from both +$length / time$ and $length * time$. It wouldn't be too safe to use such a product, right? Now we have to realize that both of the above operations (multiplication and division) are not even mathematically defined for linear algebra types such as vectors or tensors. On the other hand, two vectors @@ -34,36 +34,36 @@ results from both cases. This simply can't work. While defining quantities ISO 80000 explicitly mentions when a specific quantity has a vector or tensor character. Here are some examples: -| Quantity | Character | Quantity Equation | -|------------------------|:------------:|:-------------------------------------------------:| -| `duration` | scalar | _{base quantity}_ | -| `mass` | scalar | _{base quantity}_ | -| `length` | scalar | _{base quantity}_ | -| `path_length` | scalar | _{base quantity}_ | -| `radius` | scalar | _{base quantity}_ | -| `position_vector` | **vector** | _{base quantity}_ | -| `velocity` | **vector** | `position_vector / duration` | -| `acceleration` | **vector** | `velocity / duration` | -| `force` | **vector** | `mass * acceleration` | -| `power` | scalar | `force ⋅ velocity` | -| `moment_of_force` | **vector** | `position_vector × force` | -| `torque` | scalar | `moment_of_force ⋅ {unit-vector}` | -| `surface_tension` | scalar | `|force| / length` | -| `angular_displacement` | scalar | `path_length / radius` | -| `angular_velocity` | **vector** | `angular_displacement / duration * {unit-vector}` | -| `momentum` | **vector** | `mass * velocity` | -| `angular_momentum` | **vector** | `position_vector × momentum` | -| `moment_of_inertia` | **_tensor_** | `angular_momentum ⊗ angular_velocity` | +| Quantity | Character | Quantity Equation | +|--------------------------|:------------:|:-------------------------------------------------------:| +| $duration$ | scalar | _{base quantity}_ | +| $mass$ | scalar | _{base quantity}_ | +| $length$ | scalar | _{base quantity}_ | +| $path\; length$ | scalar | _{base quantity}_ | +| $radius$ | scalar | _{base quantity}_ | +| $position\; vector$ | **vector** | _{base quantity}_ | +| $velocity$ | **vector** | $position\; vector / duration$ | +| $acceleration$ | **vector** | $velocity / duration$ | +| $force$ | **vector** | $mass * acceleration$ | +| $power$ | scalar | $force \cdot velocity$ | +| $moment\; of\; force$ | **vector** | $position\; vector \times force$ | +| $torque$ | scalar | $moment\; of\; force \cdot \{unit\; vector\}$ | +| $surface\; tension$ | scalar | $\lvert force \rvert / length$ | +| $angular\; displacement$ | scalar | $path\; length / radius$ | +| $angular\; velocity$ | **vector** | $angular\; displacement / duration * \{unit\; vector\}$ | +| $momentum$ | **vector** | $mass * velocity$ | +| $angular\; momentum$ | **vector** | $position\; vector \times momentum$ | +| $moment\; of\; inertia$ | **_tensor_** | $angular\; momentum \otimes angular\; velocity$ | In the above equations: -- `a * b` - regular multiplication where one of the arguments has to be scalar -- `a / b` - regular division where the divisor has to be scalar -- `a ⋅ b` - dot product of two vectors -- `a × b` - cross product of two vectors -- `|a|` - magnitude of a vector -- `{unit-vector}` - a special vector with the magnitude of `1` -- `a ⊗ b` - tensor product of two vectors or tensors +- $a * b$ - regular multiplication where one of the arguments has to be scalar +- $a / b$ - regular division where the divisor has to be scalar +- $a \cdot b$ - dot product of two vectors +- $a \times b$ - cross product of two vectors +- $\lvert a \rvert$ - magnitude of a vector +- $\{unit\; vector\}$ - a special vector with the magnitude of $1$ +- $a \otimes b$ - tensor product of two vectors or tensors !!! note diff --git a/docs/users_guide/framework_basics/dimensionless_quantities.md b/docs/users_guide/framework_basics/dimensionless_quantities.md index 56961d075..589498009 100644 --- a/docs/users_guide/framework_basics/dimensionless_quantities.md +++ b/docs/users_guide/framework_basics/dimensionless_quantities.md @@ -2,7 +2,7 @@ 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 +so-called "dimensionless" quantities, which ISO defines as [quantities of dimension one](../../appendix/glossary.md#dimensionless-quantity): !!! quote "ISO/IEC Guide 99" @@ -70,8 +70,8 @@ static_assert(q.quantity_spec == isq::work / isq::heat); As shown above, the result is not of a `dimensionless` type anymore. Instead, we get a quantity type derived from the performed [quantity equation](../../appendix/glossary.md#quantity-equation). -According to the [ISQ](../../appendix/glossary.md#isq), work divided by heat is the recipe for -the thermodynamic efficiency quantity, thus: +According to the [ISQ](../../appendix/glossary.md#isq), _work_ divided by _heat_ is the recipe for +the _thermodynamic efficiency_ quantity, thus: ```cpp static_assert(implicitly_convertible(q.quantity_spec, isq::efficiency_thermodynamics)); @@ -91,7 +91,7 @@ Now, let's see what happens when we divide two quantities of the same type but d constexpr QuantityOf auto q = isq::height(4 * km) / isq::height(2 * m); ``` -This time we still get a quantity of `dimensionless` type with a `dimension_one` as its dimension. +This time, we still get a quantity of the `dimensionless` type with a `dimension_one` as its dimension. However, the resulting unit is not `one` anymore: ```cpp @@ -101,16 +101,16 @@ static_assert(q.unit == mag_power<10, 3> * one); 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 +First, it may look surprising, but this is consistent with dividing 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](https://en.wikipedia.org/wiki/Hubble%27s_law#Dimensionless_Hubble_constant) +a [_Hubble's constant_](https://en.wikipedia.org/wiki/Hubble%27s_law#Dimensionless_Hubble_constant) that uses a unit that is proportional to the ratio of kilometers per megaparsecs, which are both -units of length: +units of _length_: ```cpp inline constexpr struct hubble_constant : @@ -123,12 +123,12 @@ inline constexpr struct hubble_constant : 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 +- 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 +Thanks to assigning strong names to such quantities, later on, they can be explicitly used as arguments in the [quantity equations](../../appendix/glossary.md#quantity-equation) of other quantities deriving from them. @@ -165,17 +165,17 @@ inline constexpr struct per_mille : named_unit(radius)` respectively. +Special, often controversial, examples of dimensionless quantities are an _angular measure_ +and _solid angular measure_ quantities that are defined in the [ISQ](../../appendix/glossary.md#isq) +to be the result of a division of $arc\; length / radius$ and $area / radius^2$ respectively. Moreover, [ISQ](../../appendix/glossary.md#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](../../appendix/glossary.md#kind) of `dimensionless`. +expressed in the unit `one`. This means that both _angular measure_ and _solid angular measure_ +should be of a [kind](../../appendix/glossary.md#kind) dimensionless. -On the other hand, [ISQ](../../appendix/glossary.md#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`. +On the other hand, [ISQ](../../appendix/glossary.md#isq) also specifies that a unit radian can +be used for _angular measure_, and a unit steradian can be used for _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 +that both _angular measure_ and _solid angular measure_ should also be [quantity kinds](../../appendix/glossary.md#kind) by themselves. !!! note @@ -187,8 +187,8 @@ that both `isq::angular_measure` and `isq::solid_angular_measure` should also be ## 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 +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 @@ -245,4 +245,4 @@ inline constexpr struct steradian : named_unit<"sr", square(metre) / square(metr inline constexpr struct bit : named_unit<"bit", one, kind_of> {} bit; ``` -but still allow a usage of `one` and its scaled versions for such quantities. +but still allow the usage of `one` and its scaled versions for such quantities. diff --git a/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md b/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md index 454ea2715..a87b2434f 100644 --- a/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md +++ b/docs/users_guide/framework_basics/faster_than_lightspeed_constants.md @@ -1,8 +1,8 @@ # Faster-than-lightspeed Constants In most libraries, physical constants are implemented as constant (possibly `constexpr`) -quantity values. Such an approach has some disadvantages, often resulting in longer -compilation times and a loss of precision. +quantity values. Such an approach has some disadvantages, often affecting the run time +performance and causing a loss of precision. ## Simplifying constants in an equation @@ -16,7 +16,7 @@ performance and often a better precision of the resulting value. ## Physical constants as units -The **mp-units** library allows and encourages implementing physical constants as +The **mp-units** library allows and encourages the implementation of physical constants as regular units. With that, the constant's value is handled at compile-time, and under favorable circumstances, it can be simplified in the same way as all other repeated units do. If it is not simplified, the value is stored in a type, and the expensive @@ -53,7 +53,7 @@ inline constexpr struct magnetic_constant : ## Usage examples -With the above definitions, we can calculate vacuum permittivity as: +With the above definitions, we can calculate _vacuum permittivity_ as: ```cpp constexpr auto permeability_of_vacuum = 1. * si::magnetic_constant; @@ -72,9 +72,9 @@ permittivity of vacuum = 1 μ₀⁻¹ c⁻² = 8.85419e-12 F/m As we can clearly see, all the calculations above were just about multiplying and dividing the number `1` with the rest of the information provided as a compile-time type. Only when -a user wants a specific SI unit as a result the unit ratios are lazily resolved. +a user wants a specific SI unit as a result, the unit ratios are lazily resolved. -Another similar example can be an equation for total energy: +Another similar example can be an equation for _total energy_: ```cpp QuantityOf auto total_energy(QuantityOf auto p, diff --git a/docs/users_guide/framework_basics/generic_interfaces.md b/docs/users_guide/framework_basics/generic_interfaces.md index 9bdd57f5d..c3c4cefa8 100644 --- a/docs/users_guide/framework_basics/generic_interfaces.md +++ b/docs/users_guide/framework_basics/generic_interfaces.md @@ -1,6 +1,6 @@ # Generic Interfaces -Using a concrete unit in the interface often has a lot of sense. It is especially useful if we +Using a concrete unit in the interface often makes a lot of sense. It is especially useful if we store the data internally in the object. In such a case, we have to select a specific unit anyway. For example, let's consider a simple storage tank: @@ -30,8 +30,7 @@ However, in many cases, using a specific unit in the interface is counterproduct the following function: ```cpp -quantity avg_speed(quantity distance, - quantity duration) +quantity avg_speed(quantity distance, quantity duration) { return distance / duration; } @@ -40,28 +39,28 @@ quantity avg_speed(quantity distance, Everything seems fine for now. It also works great if we call it with: ```cpp -quantity s1 = avg_speed(220 * km, 2 * h); +quantity s1 = avg_speed(220 * km, 2 * h); ``` However, if the user starts doing the following: ```cpp -quantity s2 = avg_speed(140 * mi, 2 * h); -quantity s3 = avg_speed(20 * m, 2 * s); +quantity s2 = avg_speed(140 * mi, 2 * h); +quantity s3 = avg_speed(20 * m, 2 * s); ``` some issues start to be clearly visible: 1. The arguments must be converted to units mandated by the function's parameters at each call. This involves potentially expensive multiplication/division operations at runtime. -2. After the function returns the speed in a unit of `km/h`, another potentially expensive - multiplication/division operations have to be performed to convert the resulting quantity into +2. After the function returns the _speed_ in a unit of `km/h`, another potentially expensive + multiplication/division operations must be performed to convert the resulting quantity into a unit being the derived unit of the initial function's arguments. -3. Besides the obvious runtime cost, some unit conversions may result in a data truncation which +3. Besides the obvious runtime cost, some unit conversions may result in a value truncation, which means that the result will not be exactly equal to a direct division of the function's arguments. 4. We have to use a floating-point representation type (the `quantity` class template by default uses `double` as a representation type) which is considered - [value preserving](value_conversions.md#value-preserving-conversions). + [value-preserving](value_conversions.md#value-preserving-conversions). Trying to use an integral type in this scenario will work only for `s1`, while `s2` and `s3` will fail to compile. Failing to compile is a good thing here as the library tries to prevent the user from doing a clearly wrong thing. To make the code compile, the user needs to use @@ -72,7 +71,7 @@ some issues start to be clearly visible: quantity s3 = avg_speed((20 * m).force_in(km), (2 * s).force_in(h)); ``` - but the above will obviously provide an incorrect behavior (e.g. division by `0` in the evaluation + but the above will obviously provide an incorrect behavior (e.g., division by `0` in the evaluation of `s3`). @@ -87,15 +86,15 @@ auto avg_speed(auto distance, auto duration) } ``` -Beware that there are better solutions than this. The above code is too generic. Such a function template +Beware, this is not a good solution. The above code is too generic. Such a function template accepts everything: - quantities of other types - - the compiler will not prevent accidental reordering of the function's arguments - - quantities of different types can be passed as well -- plain `double` arguments + - the compiler will not prevent accidental reordering of the function's arguments, + - quantities of different types can be passed as well, +- plain `double` arguments, - `std::vector` and `std::lock_guard` will be accepted as well (of course, this will fail in the - function's body later in the compilation process) + instantiation of a function's body later in the compilation process). !!! note @@ -110,16 +109,39 @@ accepts everything: Much better generic code can be implemented using [basic concepts](concepts.md) provided with the library: -```cpp -auto avg_speed(QuantityOf auto distance, - QuantityOf auto duration) -{ - return isq::speed(distance / duration); -} -``` +=== "Original template notation" + + ```cpp + template + requires QuantityOf && QuantityOf + auto avg_speed(Distance distance, Duration duration) + { + return isq::speed(distance / duration); + } + ``` + +=== "The shorthand notation" + + ```cpp + template Distance, QuantityOf Duration> + auto avg_speed(Distance distance, Duration duration) + { + return isq::speed(distance / duration); + } + ``` + +=== "Terse notation" + + ```cpp + auto avg_speed(QuantityOf auto distance, + QuantityOf auto duration) + { + return isq::speed(distance / duration); + } + ``` This explicitly states that the arguments passed by the user must not only satisfy -a [`Quantity`](concepts.md#Quantity) concept but also their quantity specification must +a [`Quantity`](concepts.md#Quantity) concept, but also their quantity specification must be implicitly convertible to `isq::length` and `isq::time` accordingly. This no longer leaves room for error while still allowing the compiler to generate the most efficient code. @@ -127,7 +149,7 @@ room for error while still allowing the compiler to generate the most efficient Please note that now it is safe just to use integral types all the way which again improves the runtime performance as the multiplication/division operations are often - faster on integral rather than floating-point types. + faster on the integral rather than floating-point types. ## Constraining function template return type @@ -156,7 +178,7 @@ Doing so has two important benefits: ## Constraining a variable on the stack -If we know exactly what the function does in its internals and if we know the exact argument types +If we know precisely what the function does in its internals and if we know the exact argument types passed to such a function, we often know the exact type that will be returned from its invocation. However, if we care about performance, we should often use the generic interfaces described in this @@ -171,7 +193,17 @@ auto s2 = avg_speed(140 * mi, 2 * h); auto s3 = avg_speed(20 * m, 2 * s); ``` -In this case, it is probably OK to do so as the `avg_speed` function name explicitly provides +or benefit from CTAD: + +```cpp +quantity s1 = avg_speed(220 * km, 2 * h); +quantity s2 = avg_speed(140 * mi, 2 * h); +quantity s3 = avg_speed(20 * m, 2 * s); +``` + +*[CTAD]: Class Template Argument Deduction + +In both cases, it is probably OK to do so as the `avg_speed` function name explicitly provides the information on what to expect as a result. In other scenarios where the returned quantity type is not so obvious, it is again helpful to @@ -183,7 +215,7 @@ QuantityOf auto s2 = avg_speed(140 * mi, 2 * h); QuantityOf auto s3 = avg_speed(20 * m, 2 * s); ``` -Again this explicitly provides additional information about the quantity we are dealing with in +The above explicitly provides additional information about the quantity we are dealing with in the code, and it serves as a unit test checking if the "thing" returned from a function is actually what we expected here. @@ -192,4 +224,4 @@ what we expected here. The `QuantityOf` and `QuantityPointOf` concepts are probably the most useful, but there are a few more to play with. A list of all the concepts can be found in - [the "Basic Concepts" chapter](concepts.md). + the [Basic Concepts](concepts.md) chapter. diff --git a/docs/users_guide/framework_basics/quantity_arithmetics.md b/docs/users_guide/framework_basics/quantity_arithmetics.md index 5452d5bcd..ceb352626 100644 --- a/docs/users_guide/framework_basics/quantity_arithmetics.md +++ b/docs/users_guide/framework_basics/quantity_arithmetics.md @@ -8,8 +8,8 @@ properly constrained set of arithmetic operations on one or two operands. !!! important "Important: `quantity` propagates the underlying interface" Every single arithmetic operator is exposed by the `quantity` class template only if - the underlying representation type provides it as well and its implementation has proper - semantics (e.g. returns a reasonable type). + the underlying representation type provides it as well, and when its implementation has proper + semantics (e.g., returns a reasonable type). For example, in the following code, `-a` will compile only if `MyInt` exposes such an operation as well: @@ -22,10 +22,10 @@ quantity b = -a; Assuming that: - `q` is our quantity, -- `qq` is a quantity implicitly convertible to `q`, -- `q2` is any other quantity, -- `kind` is a [quantity of the same kind](systems_of_quantities.md#quantities-of-the-same-kind) as `q`, -- `one` is a [quantity of `dimension_one` with the unit `one`](dimensionless_quantities.md), +- `qi` is a quantity implicitly convertible to `q`, +- `qk` is a [quantity of the same kind](systems_of_quantities.md#quantities-of-the-same-kind) as `q`, +- `q1` is a [quantity of `dimension_one` with the unit `one`](dimensionless_quantities.md), +- `qq` is any other quantity, - `number` is a value of a type "compatible" with `q`'s representation type, here is the list of all the supported operators: @@ -38,26 +38,26 @@ here is the list of all the supported operators: - `--q` - `q--` - compound assignment: - - `q += qq` - - `q -= qq` - - `q %= qq` + - `q += qi` + - `q -= qi` + - `q %= qi` - `q *= number` - - `q *= one` + - `q *= q1` - `q /= number` - - `q /= one` + - `q /= q1` - binary: - - `q + kind` - - `q - kind` - - `q % kind` - - `q * q2` + - `q + qk` + - `q - qk` + - `q % qk` + - `q * qq` - `q * number` - `number * q` - - `q / q2` + - `q / qq` - `q / number` - `number / q` - ordering and comparison: - - `q == kind` - - `q <=> kind` + - `q == qk` + - `q <=> qk` As we can see, there are plenty of operations one can do on a value of a `quantity` type. As most of them are obvious, in the following chapters, we will discuss only the most important or non-trivial @@ -106,7 +106,7 @@ static_assert(isq::radius(1 * m) - 0.5 * m == isq::radius(0.5 * m)); static_assert((isq::height(1 * m) += isq::length(1 * m)) == 2 * m); // Compile-time error(3) ``` - 1. Floating-point to integral representation type is [considered narrowing](value_conversions.md). + 1. The floating-point to integral representation type is [considered narrowing](value_conversions.md). 2. Conversion of quantity with integral representation type from a unit of a higher resolution to the one with a lower resolution is [considered narrowing](value_conversions.md). 3. Conversion from a more generic quantity type to a more specific one is @@ -130,9 +130,9 @@ static_assert(isq::height(3 * m) * 0.5 == isq::height(1.5 * m)); static_assert((isq::height(3 * m) *= 0.5) == isq::height(1.5 * m)); // Compile-time error(1) ``` - 1. Floating-point to integral representation type is [considered narrowing](value_conversions.md). + 1. The floating-point to integral representation type is [considered narrowing](value_conversions.md). -However, suppose we multiply or divide quantities of the same or different types, or we divide a raw +However, suppose we multiply or divide quantities of the same or different types or we divide a raw number by a quantity. In that case, we most probably will end up in a quantity of yet another type: ```cpp @@ -169,7 +169,7 @@ of different quantity types, we do not convert quantity values to a common unit !!! important "Important: Beware of integral division" The physical units library can't do any runtime branching logic for the division operator. - All logic has to be done at compile-time when the actual values are not known, and the quantity types + All logic must be done at compile-time when the actual values are unknown, and the quantity types can't change at runtime. If we expect `120 * km / (2 * h)` to return `60 km / h`, we have to agree with the fact that @@ -183,7 +183,7 @@ of different quantity types, we do not convert quantity values to a common unit ## Modulo -Now that we know how addition, subtraction, multiplication, and division work, it is time to talk about +Now that we know how addition, subtraction, multiplication, and division work, it is time to discuss modulo. What would we expect to be returned from the following quantity equation? ```cpp @@ -278,7 +278,7 @@ static_assert(1 * h % (59 * min) == 1 * min); ## Comparison against zero In our code, we often want to compare the value of a quantity against zero. For example, we do it -every time when we want to ensure that we deal with a non-zero or positive value. +every time we want to ensure that we deal with a non-zero or positive value. We could implement such checks in the following way: @@ -287,7 +287,7 @@ if (q1 / q2 != 0 * m / s) // ... ``` -The above would work (assuming we are dealing with the quantity of speed), but could be suboptimal +The above would work (assuming we are dealing with the quantity of speed) but could be suboptimal if the result of `q1 / q2` is not expressed in `m / s`. To eliminate the need for conversion, we need to write: @@ -323,16 +323,15 @@ if (is_neq_zero(q1 / q2)) Those functions will work with any type `T` that exposes `zero()` member function returning something comparable to `T`. Thanks to that, we can use them not only with quantities but also - with [quantity points](the_affine_space.md#quantity_point), - [`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration) or any other type - that exposes such an interface. + with [`std::chrono::duration`](https://en.cppreference.com/w/cpp/chrono/duration) or any other + type that exposes such an interface. ## Other maths This chapter scopes only on the `quantity` type's operators. However, there are many named math -functions provided in the _mp-units/math.h_ header file. Among others, we can find there -the following: +functions taking quantities as arguments. Those can be found in the _mp-units/math.h_ header file. +Among others, we can find there the following: - `pow()`, `sqrt()`, `cbrt()`, - `exp()`, @@ -347,4 +346,4 @@ the following: - `asin()`, `acos()`, `atan()`. In the library, we can also find _mp-units/random.h_ header file with all the pseudo-random number -generators. +generators working on quantity types. diff --git a/docs/users_guide/framework_basics/simple_and_typed_quantities.md b/docs/users_guide/framework_basics/simple_and_typed_quantities.md index 73be74234..0de6c48ad 100644 --- a/docs/users_guide/framework_basics/simple_and_typed_quantities.md +++ b/docs/users_guide/framework_basics/simple_and_typed_quantities.md @@ -139,7 +139,7 @@ error: could not convert 'mp_units::operator* >()>()> avg_speed(mp_units::quantity()>, mp_units::quantity()>)': @@ -196,7 +196,7 @@ As we can see above, the compilation error is longer but still relatively easy t Based on the previous example, it might seem that typed quantities are not that useful, more to type and provide harder-to-understand error messages. It might be true in some cases, -but there are scenarios where they offer an additional level of safety. +but there are scenarios where they offer additional level of safety. Let's see another example: @@ -414,9 +414,9 @@ quantities-related issues, this should be the first function to look for. requested conversion is exactly what you need in this case. -## Which mode to use in my project? +## Which mode should I use in my project? -In case you wonder which mode you should choose for your project, we have good news for you. +We have good news for you if you wonder which mode you should choose for your project. Simple and typed quantity modes can be freely mixed with each other. When you use different quantities of the same kind (e.g., _radius_, _wavelength_, _altitude_, ...), you should probably reach for typed quantities to bring additional safety for those cases. Otherwise, just use diff --git a/docs/users_guide/framework_basics/value_conversions.md b/docs/users_guide/framework_basics/value_conversions.md index 2b6344366..2181d986b 100644 --- a/docs/users_guide/framework_basics/value_conversions.md +++ b/docs/users_guide/framework_basics/value_conversions.md @@ -8,9 +8,9 @@ std::cout << q1.in(m) << '\n'; quantity q2 = q1; ``` -The second line above converts the current quantity to the one expressed in metres and prints its -contents. The third line converts the quantity expressed in kilometres into the one measured -in metres. +The second line above converts the current quantity to the one expressed in meters and prints its +contents. The third line converts the quantity expressed in kilometers into the one measured +in meters. In case a user would like to perform an opposite transformation: @@ -65,7 +65,7 @@ reviews or while chasing a bug in the source code. `q.force_numerical_value_in(U)`. Another place where this cast is useful is when a user wants to convert a quantity with -a floating-point representation to the one using an integral one. Again this is a truncating +a floating-point representation to the one using an integral one. Again, this is a truncating conversion, so an explicit cast is needed: ```cpp @@ -74,7 +74,7 @@ quantity q3 = value_cast(3.14 * m); !!! info - It is often fine to use an integral as a representation type, but in general, floating-point + It is often OK to use an integral as a representation type, but in general, floating-point types provide better precision and are privileged in the library as they are considered to be value-preserving.