From f34589030758df4a4bd664520283b4913f72569c Mon Sep 17 00:00:00 2001 From: Klas Marcks Date: Thu, 14 Mar 2024 19:36:00 +0100 Subject: [PATCH] Update readme.md --- README.md | 108 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 276e08c..e7140c0 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,10 @@ Unit c = s * a; std::cout << c.value << std::endl; // prints 5e-08 ``` -If you need a non-SI unit you define it by declaring a simple struct. This is how you would define the unit -`degree_Fahrenheit`: +If you need a non-SI unit you define it by declaring a Non_coherent_unit. This is how you would define the unit `degree_Fahrenheit`: ```c++ - struct degree_Fahrenheit : Non_coherent_unit<1.0f / 1.8f, -32.0f, degree_Celsius> { - using Non_coherent_unit<1.0f / 1.8f, -32.0f, degree_Celsius>::Base; - }; +using degree_Fahrenheit = Non_coherent_unit<1.0f / 1.8f, -32.0f, degree_Celsius>; ``` You can use the new unit like any other unit already defined in TU: @@ -71,9 +68,7 @@ target_compile_definitions(my_target PRIVATE TU_TYPE=double) ## Requirements -TU requires a c++20 compliant compiler. Specifically TU utilizes float non-type template arguments. - -For the test suite that comes with TU to work, your system needs to have support for ANSI escape sequences since the output uses colours. This should work on fairly recent Windows 10 system, linux and macOS. It might be a problem on Windows 7 though. If you find that this is a showstopper for you please let us know. If enough people run TU on systems that does not have support for ANSI escape sequences, we will remove it. +TU requires a c++20 compliant compiler. For the test suite that comes with TU to work, your system needs to have support for ANSI escape sequences since the output uses colours. This should work on fairly recent Windows 10 system, linux and macOS. It might be a problem on Windows 7 though. If you find that this is a showstopper for you please let us know. If enough people run TU on systems that does not have support for ANSI escape sequences, we will remove it. ## Tested compilers @@ -153,7 +148,7 @@ TU uses official spelling of units. Therefore TU uses `litre` and `metre` and no ### Types The intrinsic data type used by TU is defined in the preprocessor macro `TU_TYPE`. -`TU_TYPE` can be `float` or `double`. All values and floating point template argumets will have the type defined by `TU_TYPE`. +`TU_TYPE` can be `float` or `double`. All values will have the type defined by `TU_TYPE`. ### Namespaces @@ -193,20 +188,22 @@ Base units are the smallest building blocks in the types system. These define po The definition of base units are done through inheritance of the `Base_unit` struct and looks as follows where the base unit is denoted `X`. ```c++ -template +template struct X : internal::Base_unit

{}; ``` The definition of `s` (second) to some power `p` then looks as ```c++ -template +template struct s : internal::Base_unit

{}; ``` +where Ratio is of type std:ratio + and a base unit `per_second` can be declared through ```c++ -s<(TU_TYPE)-1.0f>; +s; ``` #### Coherent_unit @@ -217,7 +214,13 @@ A specific coherent unit should be defined by inheriting from a `Coherent_unit` The specific coherent unit `newton` is defined as ```c++ -struct newton: Coherent_unit, m<(TU_TYPE)1.0>, kg<(TU_TYPE)1.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; +using newton = Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` i.e. it has the unit `kg m / s^2` @@ -227,7 +230,13 @@ Note that computations using seconds should use the `Coherent_unit` `second` and `second` is defined as ```c++ -struct second: Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>{}; +using second = Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` All base units are defined as `Coherent_unit`s in similar fashion. @@ -236,31 +245,23 @@ All base units are defined as `Coherent_unit`s in similar fashion. A `Non_coherent_unit` is a unit that is scaled or shifted relative to a base unit. The value of the `Non_coherent_unit` is related to the value of the base unit through `v = a * b + c` where `v` is the value of the `Non_coherent_unit`, `b` is the value of the base unit. `a` and `c` are the scaling and shift respectively. -Example of `Non_coherent_unit`s are `minute`, `hour` and `degree_Celcius`. +Examples of `Non_coherent_unit`s are `minute`, `hour` and `degree_Celcius`. A `Non_coherent_unit` is a templated struct that has the scaling factor, the shift and the base unit as template parameters. `minute` and `hour` are defined by ```c++ -struct minute : Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second> { - using Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second>::Base; -}; +using minute = Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, second>; -struct hour : Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute> { - using Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute>::Base; -}; +struct hour = Non_coherent_unit<(TU_TYPE)60.0, (TU_TYPE)0.0, minute>; ``` `degree_Celsius` is defined by ```c++ -struct degree_Celsius : Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin> { - using Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin>::Base; -}; +struct degree_Celsius = Non_coherent_unit<(TU_TYPE)1.0, (TU_TYPE)273.15, kelvin>; ``` -The `using` statement is of internal concern only. If new `Non_coherent_unit`s are created, just follow the pattern. - #### Unit The `Unit` is the intended public unit type. @@ -298,6 +299,8 @@ std::cout << ms.value << " " << mi.value << std::endl; // prints 5.0 8.3333e-5 The following prefixes are defined and can be used when creating `Unit`s. +* quecto = 10-30 +* ronto = 10-27 * yocto = 10-24 * zepto = 10-21 * atto = 10-18 @@ -319,6 +322,8 @@ The following prefixes are defined and can be used when creating `Unit`s. * exa = 1018 * zetta = 1021 * yotta = 1024 +* ronna = 1027 +* quetta = 1030 ### Functions @@ -368,14 +373,20 @@ std::cout << cu.base_value << std::endl; // prints 3900.0 This is because TU does not know what `Unit` to construct from the operation. TU falls back on the fundamental `Coherent_unit`s and `cu` will be of type ```c++ -Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>; +Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` Note also that `Coherent_unit` does not have a `value` member but only a `base_value` If we would like a specific `Unit` representation of the operation, we have to explicitly state the `Unit` as in the first example and the result of the operation will be used to construct the desired `Unit`. -Applying the `+` and `-` operators on `Unit`s that don't have the same underlying `Coherent_unit` will result in compilation failure e.g. it is not possible to add to variables of type `newton` and `second`. +Applying the `+` and `-` operators on `Unit`s that don't have the same underlying `Coherent_unit` will result in compilation failure e.g. it is not possible to add two variables of type `newton` and `second`. #### \* / @@ -400,7 +411,13 @@ std::cout << cu.base_value << std::endl; // prints 5e-08 This is because TU does not know what `Unit` to construct from the operation. TU falls back on the fundamental `Coherent_units` and `cu` will be of type ```c++ -Coherent_unit, m<(TU_TYPE)0.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)1.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>; +Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` Note also that `Coherent_unit` does not have a `value` member but only a `base_value` @@ -426,21 +443,27 @@ TU implements a `pow` operator for units. ```c++ Unit me(5.0f); -auto ch = pow<2.0f>(me); +auto ch = pow>(me); std::cout << ch.base_value << std::endl; // prints 2.5 * 10^-5 ``` `ch` will be of type ```c++ -Coherent_unit, m<(TU_TYPE)2.0>, kg<(TU_TYPE)0.0>, A<(TU_TYPE)0.0>, K<(TU_TYPE)0.0>, mol<(TU_TYPE)0.0>, cd<(TU_TYPE)0.0>>; +Coherent_unit + ,m + ,kg + ,A + ,K + ,mol + ,cd>; ``` To construct a `Unit` directly we could do ```c++ Unit me(5.0f); -Unit m2 = pow<2.0f>(me); +Unit m2 = pow>(me); std::cout << m2.value << std::endl; // prints 2.5 * 10^-2 ``` @@ -449,7 +472,7 @@ Note that `Unit` means 10-3m2 To the unit (mm)2 is equivalent to `Unit` -Note that the power is not restricted to integers. +Note that the power is restricted to std::ratio. #### sqrt @@ -461,21 +484,28 @@ sqrt(unit). is equivalent to ```c++ -pow<0.5>(unit). +pow>(unit). ``` -Note that since TU uses floating point powers, it is not guaranteed that applying first `pow<2.0>` and the `sqrt` on a unit would yield the exact unit back. - #### unop TU supports unary operations on scalar units i.e. units where all basic unit powers are `0`. Examples of scalar units is `radian` and `degree`. `unop` is a template function that applies any unary function that takes a TU_TYPE -and returns a TU_TYPE to the underlying value of the unit if it is a scalar unit. The function returns a scalar Coherent_unit initialized with the value of the performed operation. This makes it possible to operate with any unary function (subjected to the restrictions above) from the standard library on a Unit or Coherent_unit. unop can take both unary functions and lambda expressions as template parameter. +and returns a TU_TYPE to the underlying **base_value** of the unit if it is a scalar unit. The function returns a scalar Coherent_unit initialized with the value of the performed operation. This makes it possible to operate with any unary function (subjected to the restrictions above) from the standard library on a Unit or Coherent_unit. unop can take both unary functions and lambda expressions as template parameter. ```c++ -Unit angle(90); -std::cout << unop(angle).base_value; // prints 1 +Unit angle_d(90); +std::cout << unop(angle_d).base_value; // prints 1 + +Unit angle_r(PI); +std::cout << unop(angle_r).base_value; // prints 1 + +constexpr auto lambda = [](TU_TYPE v) { + return v + (TU_TYPE)1.0; +}; + +std::cout << unop(angle_d).base_value; // prints 2.5708 i.e. PI/2.0 + 1.0 ``` Note that `unop` operates on the `base_value` on a unit. In the case of `degree` the base unit is `radian` (90 degrees == pi/2 radians) and the `std::sin` function yields the correct result.