mpusz / mp-units Goto Github PK
View Code? Open in Web Editor NEWThe quantities and units library for C++
Home Page: https://mpusz.github.io/mp-units/
License: MIT License
The quantities and units library for C++
Home Page: https://mpusz.github.io/mp-units/
License: MIT License
e.g: checkout automatically modifies line endings in following png files:
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: doc/downcast_1.png
modified: doc/downcast_2.png
modified: doc/units_uml.png
andy@:~/cpp/projects/std_units/units$ git checkout andy_master
error: Your local changes to the following files would be overwritten by checkout:
doc/downcast_1.png
doc/downcast_2.png
doc/units_uml.png
Please, commit your changes or stash them before you can switch branches.
Aborting
########################################################
#########################################################
andy@:~/cpp/projects/std_units/units$ git checkout andy_master
M .gitattributes
Switched to branch 'andy_master'
andy@:~/cpp/projects/std_units/units$
Convert units::ratio
to a class NTTP.
References:
Have you thought about the possibility of having a rational exponent value? Currently the exponent value is an int
, and while usually integer exponents are of the most interest, rational exponents can appear in science and engineering when dealing with empirical relations and power laws. Alternatively, sometimes the quantity of interest (as opposed to an intermediate part of some larger calculation) contains some rational exponent, such as an amplitude spectral density[1], which has units of V/Hz^(1/2).
Also, it looks like Boost.Units supports rational exponents[2], so perhaps this should be supported here as well. I might be interested in trying this myself if you think it's appropriate. Of course, a follow-up to that would be to figure out how to handle calculating powers and roots of such units (and more generally other mathematical functions).
[1] https://en.wikipedia.org/wiki/Spectral_density#Explanation
[2] https://www.boost.org/doc/libs/1_70_0/doc/html/boost_units/Dimensional_Analysis.html
Like it or not temporaries will leak out in error messages,
therefore I propose a shorter syntax, just use the base_dim_xx direct rather than the exp<base_dim_xx,N,D>
( and lose "base_" part)
now
quantity<
unit<
dimension<
exp<base_dim_current, 12, 1>,
exp<base_dim_length, -12, 1>,
exp<base_dim_mass, -6, 1>,
exp<base_dim_time, 24, 1>
>,
ratio<1>
>,
double
> {};
to :
quantity<
unit<
dimension<
dim_length<1>,
dim_time<-1>,
dim_mass<2>,
dim_temperature<3>
>,
3 // <-- default integer exponent for si uint with default multiplier of 1
>,
double
>{};
dim_length doesn't use a default second rational numerator arg as that too will leak out and so lengthen error messages. Where rational exponents of base dimension are required use a different type e.g dim_length ## _ratio <1,2> etc
https://github.com/kwikius/pqs/blob/master/src/include/pqs/bits/base_dimension.hpp#L37
similar for units with non integer exponents, and/or multipliers
https://github.com/kwikius/pqs/blob/master/src/include/pqs/bits/unit.hpp
std::chrono is based on the difference between a point on the time dimension (time_point) and the difference between two such points, a quantity (a duration for the time dimension).
Do you plan to add such a dimension-point in your library?
Right now base units in a dimension are ordered by their name. This is good because it ensures unique identifiers and their ordering. However, most of the human-readable definitions of SI units are in a specific fix order. For example: V = kg⋅m^2/s^3/A
. Should we somehow enforce a similar ordering to improve:
For example, it might be done in the following way:
struct base_dim_length : base_dimension<"1:length", "m"> {};
struct base_dim_mass : base_dimension<"0:mass", "kg"> {};
struct base_dim_time : base_dimension<"3:time", "s"> {};
struct base_dim_current : base_dimension<"4:current", "A"> {};
struct base_dim_temperature : base_dimension<"5:temperature", "K"> {};
struct base_dim_substance : base_dimension<"2:substance", "mol"> {};
struct base_dim_luminous_intensity : base_dimension<"6:luminous intensity", "cd"> {};
Raise coherent quantity to fractional power doesnt give correct result. Personally I am not so bothered about incoherent quantities but for coherent quantities this can be done better.
Currently doesnt give the correct answer:
For coherent quantities the multiplier of the result should remain as one ,and the exponent should be adjusted ( so for square root divide exponent by 2, and in fact for pow<R>(q) the result exponent is simply multiply the exponent by R ( so for square root multiply by 1/2, for cube 1/3, for pow<3/2> multiply by 3/2. If the exponent is a rational number then it can represent the quantity raised to fractional power correctly and exactly .
The more I think about it the more I think that UDLs may not be the right tool for the job. Yeah, we used it in std::chrono
and it seems nice to write auto v = 120km / 2h;
. However, they could be replaced with constants. For example:
namespace si {
inline namespace unit_constants { // is it a good name?
inline constexpr length<metre> m(1);
}
}
Here are a few issues that I see with UDLs:
UDLs are only for compile-time known values. Currently with UDLs:
using namespace units::si;
auto v1 = 120km / 2h;
auto v2 = length<kilometre>(length) / time<hour>(duration);
with constants those 2 cases would look like:
auto v1 = 120 * km / 2 / h;
auto v2 = length * km / duration / h;
Constants treat both cases in a unified way. It is also worth to notice that we work mostly with runtime variables and compile-time known values appear only in physical constants and unit tests.
UDLs for some units may be impossible to achieve in C++. I already found issues with F
(farad), J
(joule), W
(watt), K
(kelvin), d
(day), l
or L
(litre), erg
, ergps
. It is probably still not the complete list here. All of those problems originated from the fact that those numeric symbols are already used in literals (sometimes compiler extensions but still). I am afraid that at for some of those cases we will not be able to fix it or workaround it in the C++ specification. None of those issues affect constants.
UDLs cannot be disambiguated with the namespace name:
using namespace si;
auto d = 1cm; // quantity<si::dim_length, si::centimetre>
using namespace cgs;
auto d = 1cm; // quantity<cgs::dim_length, si::centimetre>
using namespace si;
using namespace cgs;
auto d = 1cm; // FAILS TO COMPILE
With constants it is simple:
using namespace si;
using namespace cgs;
auto d1 = 1 * si::cm; // quantity<si::dim_length, si::centimetre>
auto d2 = 1 * cgs::cm; // quantity<cgs::dim_length, si::centimetre>
So maybe we should prefer constants over UDLs? If so should they be put to an inner inlined namespace (like literals
)?
Let's vote:
(please vote only once by clicking on the correct bar above)
For some cases (serialization) the user may want to disable Unicode text output and just use ASCII letters. For example, we could use 'A' specifier to ASCII-only output (specifier letter a subject for bikeshedding). It means that:
symbol
static members in every unitThere are a few pairs (or more) quantities that have the same quantity:
It is not clear how to handle those. Should the library:
I'm curious to your thoughts on how this applies beyond scalar quantities. How might this be combined with a linear algebra library like eigen?
Let's discuss the best way to support physical constants.
First of all a few requirements:
latest
namespace/flag because we will not be able to change it in the future as this would be an ABI break and the ISO C++ Committee hates ABI breaks.total_energy
).There are several design options here:
namespace units::si::si2019 {
inline constexpr auto speed_of_light = 299792458q_mps;
inline constexpr auto planck_constant = 6.62607015e-34q_J * 1q_s;
}
Energy auto total_energy(Momentum auto p, Mass auto m, Velocity auto c)
{
return sqrt(pow<2>(p * c) + pow<2>(m * pow<2>(c)));
}
const Energy auto E = total_energy(p, m, si::si2019::speed_of_light);
si
)Rep
type fixed by a specific UDL (not compatible with C++20 mathematical constants)c
from 2019, h
before 2019)namespace units::si::si2019 {
template<Scalar Rep = double>
inline constexpr auto speed_of_light = velocity<metre_per_second, Rep>(299792458);
template<Scalar Rep = double>
inline constexpr auto planck_constant = energy<joule, Rep>(6.62607015e-34) * time<second, Rep>(1);
}
Energy auto total_energy(Momentum auto p, Mass auto m, Velocity auto c)
{
return sqrt(pow<2>(p * c) + pow<2>(m * pow<2>(c)));
}
const Energy auto E = total_energy(p, m, si::si2019::speed_of_light<>);
si
)Rep
type parametrized (compatible with C++20 mathematical constants)c
from 2019, h
before 2019)namespace units::constants {
template<Version V, Scalar Rep = double>
inline constexpr auto planck_constant = unspecified;
template<Version V, Scalar Rep = double>
inline constexpr auto speed_of_light = unspecified;
}
namespace units {
namespace si {
struct si2019 : version {};
} // namespace si
namespace constants {
template<Scalar Rep>
inline constexpr auto planck_constant<si::si2019, Rep> = si::energy<si::joule, Rep>(6.62607015e-34) * si::time<si::second, Rep>(1);
template<Scalar Rep>
inline constexpr auto speed_of_light<si::si2019, Rep> = si::velocity<si::metre_per_second, Rep>(299792458);
}
}
template<Version V>
Energy auto total_energy(Momentum auto p, Mass auto m)
{
constexpr auto c = constants::speed_of_light<V>;
return sqrt(pow<2>(p * c) + pow<2>(m * pow<2>(c)));
}
const Energy auto E = total_energy<si2019>(p, m);
version
Rep
type parametrized (compatible with C++20 mathematical constants)Let's vote:
(please vote only once by clicking on the correct bar below)
Currently, it is unclear on how to handle a logarithmic (or other scales). There is only one library on the market that provides such a built-in support https://github.com/nholthaus/units
There is a lack of consistency in _t
prefix should be used or not inside the library.
The following code compiles and outputs 288
while it shouldn't.
#include <iostream>
#include <units/dimensions/velocity.h>
#include <units/dimensions/acceleration.h>
units::Acceleration acc(units::Velocity l, units::Time t)
{
return l * t;
}
int main()
{
using namespace units::literals;
std::cout << acc(144.km / 1.h, 2.h).count();
}
The following works correctly:
units::Acceleration acc(units::quantity<units::metre_per_second> l, units::quantity<units::second> t)
{
return l * t;
}
So, this might be a implementation problem with concepts?
Some converters between duration
and quantity
might be provided
type_list
operationscommon_ratio
measurement
ISO 80000-1:2009(E)
- 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.
Assuming:
auto q1 = quantity<metre, double>() / quantity<metre, double>();
auto q2 = quantity<second, double>() / quantity<second, double>();
What the result should be?
(please vote only once by clicking on the correct bar above)
Option 1 (current library design)
static_assert(std::is_same_v<q1, double>);
static_assert(std::is_same_v<q2, double>);
auto q = q1 + q2;
static_assert(std::is_same_v<q, double>);
Option 2
static_assert(std::is_same_v<q1::dimension, dimension<>>);
static_assert(std::is_same_v<q2::dimension, dimension<>>);
auto q = q1 + q2;
static_assert(std::is_same_v<q::dimension, dimension<>>);
Option 3
static_assert(std::is_same_v<q1::dimension, dimension<exp<base_dim_length, 0>>>);
static_assert(std::is_same_v<q2::dimension, dimension<exp<base_dim_time, 0>>>);
// auto q = q1 + q2; // does not compile
Please note that in such a case:
auto q1 = 10mps * 2s; // length
auto q2 = q1 / 2m; // dimensionless<length>
auto q = 10mps * 2s / 2m; // dimensionless<velocity>
Similarly to derived_dimension
having support for derived dimensions in exponents lists:
struct amplitude_spectral_density : derived_dimension<amplitude_spectral_density, units::exp<voltage, 1>, units::exp<frequency, -1, 2>> {};
derived_unit
should have similar support for composing a unit from derived units of other dimensions:
struct volt_per_sq_hertz : derived_unit<volt_per_sq_hertz, amplitude_spectral_density, volt, hertz> {};
The more I think about the "number" concept (#28) the more doubts I have. I see 2 solutions here:
Option 1
template<Unit U, Number Rep = double>
class quantity {
public:
template<Number Value>
constexpr quantity& operator%=(const Value& rhs);
// ...
};
In this case, Rep
has to satisfy all of the requirements of the Number
concepts. It means that even if the user is never going to use operator %=
on a quantity
his/her representation type has to provide it or the quantity
class template instantiation will fail.
Option 2
template<typename T>
concept UnitRep = std::regular<T> && std::totally_ordered<T>;
template<Unit U, UnitRep Rep = double>
class quantity {
public:
template<Number Value>
constexpr quantity& operator%=(const Value& rhs)
requires requires(Rep v) { { v %= rhs } -> std::same_as<Rep&>; };
// ...
};
In this case, the user will be able to instantiate the quantity
class template for every "sane" type and will be able to use only those arithmetic operations that are supported by the underlying Rep
type.
Which option do you prefer?
(please vote only once by clicking on the correct bar above)
The SI standard provides the following unit prefixes:
Name | Symbol | Value |
---|---|---|
yocto | y | 10⁻²⁴ |
zepto | z | 10⁻²¹ |
atto | a | 10⁻¹⁸ |
femto | f | 10⁻¹⁵ |
pico | p | 10⁻¹² |
nano | n | 10⁻⁹ |
micro | μ | 10⁻⁶ |
milli | m | 10⁻³ |
centi | c | 10⁻² |
deci | d | 10⁻¹ |
one | 10⁰ | |
deca | da | 10¹ |
hecto | h | 10² |
kilo | k | 10³ |
mega | M | 10⁶ |
giga | G | 10⁹ |
tera | T | 10¹² |
peta | P | 10¹⁵ |
exa | E | 10¹⁸ |
zetta | Z | 10²¹ |
yotta | Y | 10²⁴ |
These all should be supported. However, yocto
, zepto
, zetta
, and yotta
are currently not implementable (I think) because the int
s in the ratio
type are too small for these ranges.
Furthermore, for the amount of data units, the following prefixes should be provided:
Name | Symbol | Value |
---|---|---|
kibi | ki | 2¹⁰ |
mebi | Mi | 2²⁰ |
gibi | Gi | 2³⁰ |
tebi | Ti | 2⁴⁰ |
pebi | Pi | 2⁵⁰ |
exbi | Ei | 2⁶⁰ |
zebi | Zi | 2⁷⁰ |
yobi | Yi | 2⁸⁰ |
These are needed for MiB/s
, GiB/s
, ...
Following instructions at
https://github.com/mpusz/units/blob/master/doc/INSTALL.md
fails to update fmt lib and fails to link.
Here is abbreviated commands I am using
git clone --recurse-submodules https://github.com/mpusz/units.git
mkdir build && cd build
CC=gcc-9 CXX=g++-9 conan install .. -pr /home/andy/.conan/profiles/default -s compiler.cppstd=20 -b=outdated -u
CC=gcc-9 CXX=g++-9 cmake ..
cmake --build .
below is diagnostic
/cpp/projects/units_temp$ git clone --recurse-submodules https://github.com/mpusz/units.git/cpp/projects/units_temp$ mkdir units/build && cd units/build
Cloning into 'units'...
remote: Enumerating objects: 355, done.
remote: Counting objects: 100% (355/355), done.
remote: Compressing objects: 100% (216/216), done.
remote: Total 3884 (delta 193), reused 257 (delta 116), pack-reused 3529
Receiving objects: 100% (3884/3884), 963.54 KiB | 1.47 MiB/s, done.
Resolving deltas: 100% (2519/2519), done.
Checking connectivity... done.
Submodule 'cmake/common' (https://github.com/mpusz/cmake-scripts.git) registered for path 'cmake/common'
Cloning into 'cmake/common'...
remote: Enumerating objects: 58, done.
remote: Total 58 (delta 0), reused 0 (delta 0), pack-reused 58
Unpacking objects: 100% (58/58), done.
Checking connectivity... done.
Submodule path 'cmake/common': checked out 'fa85aebdd45ce88e6c2d72dedc8e1693dc419f67'
andy@andy-Aspire-ES1-521:
andy@andy-Aspire-ES1-521:~/cpp/projects/units_temp/units/build$ CC=gcc-9 CXX=g++-9 conan install .. -pr /home/andy/.conan/profiles/default -s compiler.cppstd=20 -b=outdated -u
Configuration:
[settings]
arch=x86_64
arch_build=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=20
compiler.libcxx=libstdc++
compiler.version=9.2
os=Linux
os_build=Linux
[options]
[build_requires]
[env]
fmt/6.1.0: WARN: Can't update, no package in remote
fmt/6.1.0: Package is up to date
range-v3/0.10.0@ericniebler/stable: Package is up to date
Catch2/2.11.0@catchorg/stable: Package is up to date
conanfile.py (mp-units/0.5.0): Installing package
Requirements
fmt/6.1.0 from 'conan-center' - Cache
range-v3/0.10.0@ericniebler/stable from 'conan-center' - Cache
Packages
fmt/6.1.0:51e5e7a80b9495fcaf79f641808d5f28857e09df - Cache
range-v3/0.10.0@ericniebler/stable:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Cache
Build requirements
Catch2/2.11.0@catchorg/stable from 'conan-center' - Cache
Build requirements packages
Catch2/2.11.0@catchorg/stable:5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9 - Cache
Catch2/2.11.0@catchorg/stable: Already installed!
fmt/6.1.0: Already installed!
range-v3/0.10.0@ericniebler/stable: Already installed!
conanfile.py (mp-units/0.5.0): Applying build-requirement: Catch2/2.11.0@catchorg/stable
conanfile.py (mp-units/0.5.0): Generator cmake created conanbuildinfo.cmake
conanfile.py (mp-units/0.5.0): Generator txt created conanbuildinfo.txt
conanfile.py (mp-units/0.5.0): Generated conaninfo.txt
conanfile.py (mp-units/0.5.0): Generated graphinfo
andy@andy-Aspire-ES1-521:/cpp/projects/units_temp/units/build$ CC=gcc-9 CXX=g++-9 cmake ../cpp/projects/units_temp/units/build$ cmake --build .
-- The C compiler identification is GNU 9.2.1
-- The CXX compiler identification is GNU 9.2.1
-- Check for working C compiler: /usr/bin/gcc-9
-- Check for working C compiler: /usr/bin/gcc-9 -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/g++-9
-- Check for working CXX compiler: /usr/bin/g++-9 -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: Adjusting output directories
-- Conan: Using cmake targets configuration
-- Library fmt found /home/andy/.conan/data/fmt/6.1.0///package/51e5e7a80b9495fcaf79f641808d5f28857e09df/lib/libfmt.a
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: /home/andy/cpp/projects/units_temp/units/build
-- Conan: Compiler GCC>=5, checking major version 9.2
-- Conan: Checking correct version: 9.2
-- CODE_COVERAGE=OFF
-- Performing Test HAVE_WLOGICAL_OP
-- Performing Test HAVE_WLOGICAL_OP - Success
-- Performing Test HAVE_WUSELESS_CAST
-- Performing Test HAVE_WUSELESS_CAST - Success
-- Performing Test HAVE_WDUPLICATED_COND
-- Performing Test HAVE_WDUPLICATED_COND - Success
-- Performing Test HAVE_WDUPLICATED_BRANCHES
-- Performing Test HAVE_WDUPLICATED_BRANCHES - Success
-- Performing Test HAVE_WNULL_DEREFERENCE
-- Performing Test HAVE_WNULL_DEREFERENCE - Success
-- Configuring done
-- Generating done
-- Build files have been written to: /home/andy/cpp/projects/units_temp/units/build
andy@andy-Aspire-ES1-521:
Scanning dependencies of target unit_tests_runtime
[ 3%] Building CXX object test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/catch_main.cpp.o
[ 6%] Building CXX object test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/digital_info_test.cpp.o
[ 10%] Building CXX object test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/math_test.cpp.o
[ 13%] Building CXX object test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/fmt_test.cpp.o
[ 17%] Building CXX object test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/fmt_units_test.cpp.o
[ 20%] Linking CXX executable ../../../bin/unit_tests_runtime
CMakeFiles/unit_tests_runtime.dir/fmt_test.cpp.o: In function std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > fmt::v6::internal::grouping<char>(fmt::v6::internal::locale_ref)': fmt_test.cpp:(.text._ZN3fmt2v68internal8groupingIcEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS1_10locale_refE[_ZN3fmt2v68internal8groupingIcEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEENS1_10locale_refE]+0x2e): undefined reference to
std::__cxx11::basic_string<char, std::char_traits, std::allocator > fmt::v6::internal::grouping_impl(fmt::v6::internal::locale_ref)'
collect2: error: ld returned 1 exit status
test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/build.make:144: recipe for target 'bin/unit_tests_runtime' failed
make[2]: *** [bin/unit_tests_runtime] Error 1
CMakeFiles/Makefile2:129: recipe for target 'test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/all' failed
make[1]: *** [test/unit_test/runtime/CMakeFiles/unit_tests_runtime.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2
fmt::formatter
specializationk
, K
, W
, F
conflict with gcc GNU extensions (https://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Fixed_002dPoint.html) for floating-point types.J
conflicts with imaginary constants GCC extensionerg
(CGS energy) and derived (for example ergps
) UDL conflicts with engineering syntaxd
(day) conflicts with double
floating-point suffixl
of L
for litre conflicts with integer floating-point suffixFor the fields of computer science and embedded systems it would be quite useful to have support for memory quantities (kbit, kB, kiB, MB, GB,...) and bandwidth quantities, i.e. memory quantities per time like kbit/s, MB/s and all declinations as well ( for describing data transfer capacities and measurements of all kind of memory and bus devices).
Hidden Friends are good because they help with overload resolution and thus are suggested for usage in a modern C++ design.
However, for quantity
it produces issues with implicit conversions. The second assert of the following code compiles fine even though it shouldn't: https://godbolt.org/z/kSrqHT.
When non-friend version is used it correctly fails to compile: https://godbolt.org/z/32s4cj
We could provide template parameters for both arguments of a hidden friend implementation:
https://godbolt.org/z/2uMsPB. However, in this case we end up with an ambiguous overload set. So we have to constrain it: https://godbolt.org/z/RKaopR. With this, we achieved what we wanted but with a cost of a more complicated signature.
Should we provide constrained hidden friend version of the operator or non-friend one with all its overload resolution issues?
As a dependency to this project we need a "number" concept. By this I do not mean exactly this name or a concept that have all the constraints in one place. It might be divided to smaller concepts but as an aggregate should at least satisfy something along:
template<typename T>
concept number-ish = std::regular<T> &&
std::totally_ordered<T> &&
requires(T a, T b) {
{ a + b } -> std::same_as<T>;
{ a - b } -> std::same_as<T>;
{ a * b } -> std::same_as<T>;
{ a / b } -> std::same_as<T>;
{ +a } -> std::same_as<T>;
{ -a } -> std::same_as<T>;
{ a += b } -> std::same_as<T&>;
{ a -= b } -> std::same_as<T&>;
{ a *= b } -> std::same_as<T&>;
{ a /= b } -> std::same_as<T&>;
{ T{0} };
};
The above definition is probably wrong. For some operations we should not verify the return type (a * b
might yield a different type than a / b
). We also did not account here for %
, ++v
, v++
operations that work on integral types but not on a floating-point.
Could you confirm the current implementation is uni-dimensional?
If yes,
Do you plan to manage with multi-dimensions?
Do you plan to manage with dimension-less quantities? Just a counter, as counting the number of potatos.
Hi @mpusz ,
I have a problem with the hello_units
example, when I modify it so that it reads:
auto length = si::length<international::mile>(10);
auto time = si::time<si::hour>(2);
std::cout << length * length * time << '\n';
It does not compile for me. Can you give me a hint if I am doing something wrong or it is not expected to work, yet?
Cheers,
Grzegorz
Thanks for the great library! Is there any plan to support Clang once it is C++2a feature-complete? Currently I am unable to use the library, but I'll hold off integrating with another units library if Clang support is planned.
Currently std::ratio_add
is used in dim_consolidate
. Replace with a custom implementation for a custom type.
The following code https://godbolt.org/z/7pqFV7 compiles and runs fine on both Debug and Release on gcc-9.2. It also runs fine without optimizations on gcc-10. However, trying to enable any, even -O1, makes units symbols in the library to be optimized away (https://godbolt.org/z/5ZhQs5).
It is most probably a bug in gcc rather than in the units library. I already spoke about this problem with gcc developers but they need a self-contained example with repro of this bug in order to start working on the issue. If anyone could help in creating such a code sample it would be great!
A Physical Units Library for C++ providing compile-time dimensional analysis and unit/quantity manipulation. Try it on Compiler Explorer (https://godbolt.org/z/OVpkT1)
It uses the old paths for the lib
needs to be changed to the one in the readme https://godbolt.org/z/7pqFV7 which works fine
Modules:
Framework types that should not be explicitly used by the user (i.e. dimension
, unit
) should be private in a module and only a helper interface should be publicly exposed to the user.
Provide nice Unicode symbols for fractional exponents wherever possible.
using namespace units;
using namespace units::si::literals;
std::cout << sqrt(1m) << "\n";
Sorry, this is making me feel like a beginner...
I saw your CppCon talk and I am really interested in this library and could be a potential contributor to help. It looks super promising. Great work. Played with it on godbolt, all good, lots of ideas.
I have
/usr/bin/g++ --version
g++ (Ubuntu 9.1.0-2ubuntu2~19.04) 9.1.0
couldn't get conan/cmake to work (missing common/tools...
and several other problems - another time), so I am trying just to "header only include it"
and running
/usr/bin/g++ -std=c++2a -fconcepts -I/usr/include/c++/9/ -L/usr/lib/gcc/x86_64-linux-gnu/9
but it is spewing errors about
units/src/include/units/bits/hacks.h:25:10: fatal error: concepts/concepts.hpp: No such file or directory
doesn't appear to be a paths issue, done a full find and there is no concepts.hpp
only concepts.h
which is not what we want. Is this something gcc
provides for the experimental concepts support?
I tried master and 0.4.0. Same issues.
Sorry, embarrassing, but I am stuck. Bad install of g++ v9.1 at my end, or a bad #include?
Or maybe it's easier to wait until gcc 10 is released? You did make this work on godbolt with 9.1 and 9.2 though?
The following code:
#include <iostream>
#include <units/physical/si/length.h>
#include <units/math.h>
namespace units::si
{
struct gigametre : prefixed_unit<gigametre, giga, metre> {};
} // namespace units::si
using position = units::si::length<units::si::gigametre>;
int main()
{
auto const x = position{1.};
std::cout << "x: " << x << "\n"
<< "sqrt(x): " << units::sqrt(x) << "\n"
<< "x*x: " << x*x << "\n"
<< "sqrt(x*x): " << units::sqrt(x*x) << "\n";
}
gives the following output:
$ g++ -std=c++2a -fconcepts units.cpp && ./a.out
x: 1 Gm
sqrt(x): 1 m^(1/2)
x*x: 1 × 10¹⁸ m²
sqrt(x*x): 1 m
Make all the operators hidden friends
Mpusz units on new_design branch splits into quantity_systems { physical.si, physical.cgs, data }
Does a base_dimension belong to particular quantity_system(s) or is a base_dimension allowed in any quantity_system? Or alternatively do quantity systems themselves belong to a particular quantity "universe"? (The base_dimension then exists in that universe rather than a particular quantity system.
Is there a dependency of base_dimension on the particular system(s) in use as suggested here?
https://github.com/mpusz/units/blob/new_design/src/include/units/base_dimension.h#L39
One dependency, for example might be if base-dimensions are ordered differently in different systems, or maybe two base_dimensions from different systems compare the same for ordering. Then what happens if various systems are used simultaneously?
If there is a dependency then instead of
is_base_dimension
one might have to do
is_base_dimension_of<QuantityUniverse,T>
Now the next issue. It is necessary to know what universe the computation applies to at compile time, so how one finds and applies the quantity_system a computation is in during compilation? .
(Maybe by choosing a custom header eg, as for example (std::cout availability is dependent on iostream header for example)
4.0km % 3.0km;
thankfully does not compile as %
is not supported for floating point values. The error message however is unreadable:
In file included from /opt/compiler-explorer/libs/mp-units/trunk/src/include/units/dimensions/length.h:26,
from /opt/compiler-explorer/libs/mp-units/trunk/src/include/units/dimensions/velocity.h:25,
from <source>:1:
/opt/compiler-explorer/libs/mp-units/trunk/src/include/units/quantity.h: In instantiation of 'constexpr units::Quantity units::operator%(const units::quantity<U, Rep>&, const units::quantity<U2, Rep2>&) [with U1 = units::kilometre; Rep1 = long double; U2 = units::kilometre; Rep2 = long double]':
<source>:6:20: required from here
/opt/compiler-explorer/libs/mp-units/trunk/src/include/units/quantity.h:382:45: error: invalid operands of types 'units::quantity<units::kilometre, long double>::rep' {aka 'long double'} and 'units::quantity<units::kilometre, long double>::rep' {aka 'long double'} to binary 'operator%'
382 | using common_rep = decltype(lhs.count() % rhs.count());
/opt/compiler-explorer/libs/mp-units/trunk/src/include/units/quantity.h:382:45: error: invalid operands of types 'units::quantity<units::kilometre, long double>::rep' {aka 'long double'} and 'units::quantity<units::kilometre, long double>::rep' {aka 'long double'} to binary 'operator%'
Compiler returned: 1
The question is how to fix this. Add a static_assert
to the function, or disable it via concepts?
operator<=>
should be implemented
Should operator++
and operator--
be disabled for floating point representations? Also, as for operator%
, how should these operations be disabled?
I've noticed that common_ratio
does not appear to be correctly taking into account the exponent of the ratio.
Here is a minimal example: https://godbolt.org/z/nCn3Kx
I belive this function (gcd_frac) would produce the desired behaviour. Instead of the current implementation in units/ratio.h
, common_rato_impl
.
Unfortunatly I seem to be missing the <concepts/concepts.hpp>
header to compile the library and test this out.
Hello, I am new to Conan, so maybe that is causing my problem, but I cannot get cmake to run. On line 30 of the top level cmake file there is a command to include a directory that does not exist is the source tree. What is this supposed to point to?
units/CMakeLists.txt
include(common/cmake/tools)
Here is the directory, so maybe after loading the path do include tools.cmake?
Currently such code compiles fine:
struct kilometre_per_hour : derived_unit<kilometre_per_hour, velocity, kilometre, hour, kilogram> {};
Some units require huge ratios that cannot be expressed as ratio of std::intmax_t
. This is why we need to add a new Exp
parameter that will mark power of 10 used in ratio.
Exp
ratio
parameterratio<10, 1, 0>
should have the same members as ratio<1, 1, 1>
; ratio<1, 10, 0>
should have the same members as ratio<1, 1, -1>
)Exp
to all arithmetic operations (ie. ratio_multiply
)A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.