Giter Site home page Giter Site logo

mpusz / mp-units Goto Github PK

View Code? Open in Web Editor NEW
950.0 31.0 79.0 34.54 MB

The quantities and units library for C++

Home Page: https://mpusz.github.io/mp-units/

License: MIT License

CMake 30.26% Python 0.63% C++ 68.52% C 0.57% Dockerfile 0.02%
units dimensional-analysis quantity-manipulation cpp20 cpp library system-of-units quantity units-of-measure units-of-measurement

mp-units's People

Contributors

alex-700 avatar aostrowski avatar badbadc0ffee avatar bourumir-wyngs avatar burnpanck avatar chiphogg avatar dbraeckelmann avatar dkavolis avatar fdischner avatar go2sh avatar hazardyknusperkeks avatar hofbi avatar jansende avatar johelegp avatar komputerwiz avatar kwikius avatar mikeford1 avatar mkrupcale avatar mpusz avatar nathompson avatar nebkat avatar ralphsteinhagen avatar rbrugo avatar sohamroy19 avatar thecoconutchef avatar tobylorenz avatar twon avatar uilianries avatar yasamoka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mp-units's Issues

Add modules support

Modules:

  1. Framework
  2. IO
  3. Systems (one submodule per system)
    • dimensions (one submodule per dimension)

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.

Poll: UDLs vs constants

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:

  1. 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.

  2. 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.

  3. 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)


sqrt gives wrong unit

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

Is Clang support planned?

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.

Add support for `ratio<Num, Den, Exp>`

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.

  • Add Exp ratio parameter
  • Make sure that ratio is able to simplify without issues (ratio<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>)
  • Add support for Exp to all arithmetic operations (ie. ratio_multiply)

Unicode output for fractional exponents

Provide nice Unicode symbols for fractional exponents wherever possible.

using namespace units;
using namespace units::si::literals;

std::cout << sqrt(1m) << "\n";

Poll: Dimensionless quantity (quantity of dimension one)

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>

Poll: Physical Constants

Let's discuss the best way to support physical constants.

First of all a few requirements:

  1. Constant values do change. Even if SI 2019 is intended to fix those for ages something still may change in the future. As a result, we cannot just have one global value for each constant.
  2. Old constant values are still needed to reproduce calculations so we cannot just scope on the latest version.
  3. We cannot provide any 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.
  4. In C++20 we will finally get math constants. They are variable templates parametrized on representation types.
  5. We might want to write generic functions that will work with different systems and constants (i.e. total_energy).

There are several design options here:

Option 1 (Simple)

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);
  • constants defined in their system namespace (i.e. in si)
  • versioning provided by sub-namespaces
  • we can easily use UDLs to define them
  • Rep type fixed by a specific UDL (not compatible with C++20 mathematical constants)
  • in case different versions are needed have to be passed as function arguments (or maybe NTTPs in C++23)
  • user can (accidentally) mix constants from different times/versions/releases (i.e. c from 2019, h before 2019)

Option 2 (Parametrized Rep)

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<>);
  • constants defined in their system namespace (i.e. in si)
  • versioning provided by sub-namespaces
  • we cannot use UDLs to define them
  • Rep type parametrized (compatible with C++20 mathematical constants)
  • in case different versions are needed have to be passed as function arguments (or maybe NTTPs in C++23)
  • user can (accidentally) mix constants from different times/versions/releases (i.e. c from 2019, h before 2019)

Option 3 (Globals)

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);
  • constants defined in one global namespace (outside of their system namespace)
  • versioning provided by tag types inherited from version
  • we cannot use UDLs to define them
  • Rep type parametrized (compatible with C++20 mathematical constants)
  • in case different versions are needed global access based on a version tag (no need for an additional function parameter)
  • consistent usage of different constants from the same version (if mixing of versions is needed, the user can still decay to dedicated function parameters)

Let's vote:
(please vote only once by clicking on the correct bar below)



Raise coherent quantity to fractional power doesnt give correct result.

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:

https://godbolt.org/z/6bgkEK

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 .

Support for memory and bandwidth

For 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).

Have you considered to add a dimension-point in the design?

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?

Different powers of different units

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

`operator%` should be disabled for floating point representations

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?

Add a switch to `fmt::format` to disable Unicode

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:

  • the named units and prefixes definition should allow providing up to 2 literals
  • there should be 2 symbol static members in every unit

Quantities with the same dimension

There are a few pairs (or more) quantities that have the same quantity:

  • "moment of force/torque" vs "energy/work"

It is not clear how to handle those. Should the library:

  1. Should the library work as for any other quantity when only one of the definitions ais imported (header included) to the current translation unit or should there be a special behavior for such case?
  2. What to do when both headers are included?
    a) Fail to compile
    b) No implicit downcasting to any of those and demand an explicit cast (how to implement this)?

Full build and unit testing - fails

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
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:
/cpp/projects/units_temp$ mkdir units/build && cd units/build
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 ..
-- 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:
/cpp/projects/units_temp/units/build$ cmake --build .
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

Dimension rational exponents

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

Better documentation

The order of base units in a dimension

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:

  • compile-time error messages
  • types visible in a debugger
  • printing of unknown dimensions
    ?

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"> {};

Terser syntax for temporaries

Like it or not temporaries will leak out in error messages,

https://godbolt.org/z/rhNxX4

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

Poll: How to constrain operations in a class template?

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)

Write a paper on a "number" concept

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.

Common ratio maths is incomplete

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.

basic compiling of package

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?

Does a base_dimension belong to particular quantity_system(s)?

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)

Found a bug in the dimensional analysis

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?

git automatically changes line endings in png files at checkout in unix

git automatically changes line endings in png files at checkout in unix and so creating any new branch will have the noise shown below. Issue seems to be due to first line in .gitattributes :

  • text=auto eol=lf

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

########################################################

Now commented out #* text=auto eol=lf in .gitattributes

#########################################################

andy@:~/cpp/projects/std_units/units$ git checkout andy_master

M .gitattributes

Switched to branch 'andy_master'
andy@:~/cpp/projects/std_units/units$

Add full prefix support

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 ints 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, ...

Add support for `derived_unit` of derived units

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> {};

gcc-10 optimizer issue

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!

Hidden Friends issue

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?

Installation issue

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?

image

Is the library multi-dimensional, dimension-less?

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.