Question

Does it make sens in C++ to define physics units as separate types and define valid operations between those types?

Is there any advantage in introducing a lot of types and a lot of operator overloading instead of using just plain floating point values to represent them?

Example:

class Time{...};
class Length{...};
class Speed{...};
...
Time operator""_s(long double val){...}
Length operator""_m(long double val){...}
...
Speed operator/(const Length&, const Time&){...}

Where Time, Length and Speed can be created only as a return type from different operators?

Was it helpful?

Solution

Does it make sens in C++ to define physics units as separate types and define valid operations between those types?

Absolutely. The standard Chrono library already does this for time points and durations.

Is there any advantage in introducing a lot of types and a lot of operator overloading instead of using just plain floating point values to represent them?

Yes: you can use the type system to catch errors like adding a mass to a distance at compile time, without adding any runtime overhead.

If you don't feel like defining the types and operators yourself, Boost has a Units library for that.

OTHER TIPS

I would really recommend boost::units for this. It does all the conversion compile-time and also it gives you a compile time error if you're trying using erroneous dimensions psuedo code example:

length l1, l2, l3;
area a1 = l1 * l2; // Compiles
area a2 = l1 * l2 * l3; // Compile time error, an area can't be the product of three lengths.
volume v1 = l1 * l2 * l3; // Compiles

I've gone down this road. The advantages are all the normal numerous and good advantages of type safety. The disadvantages I've run into:

  • You'll want to save off intermediate values in calculations... such as seconds squared. Having these values be a type is somewhat meaningless (seconds^2 obviously isn't a type like velocity is).
  • You'll want to do increasingly complex calculations which will require more and more overloads/operator defines to achieve.

At the end of the day, it's extremely clean for simple calculations and simple purposes. But when math gets complicated, it's hard to have a typed unit system play nice.

Everyone has mentioned the type-safety guarantees as a plus. Another HUGE plus is the ability to abstract the concept (length) from the units (meter).

So for example, a common issue when dealing with units is to mix SI with metric. When the concepts are abstracted as classes, this is no longer an issue:

Length width = Length::fromMeters(2.0);
Length height = Length::fromFeet(6.5);
Area area = width * height; //Area is computed correctly!
cout << "The total area is " << area.toInches() << " inches squared.";

The user of the class doesn't need to know what units the internal-representation uses... at least, as long as there are no severe rounding issues.


I really wish more trigonometry libraries did this with angles, because I always have to look up whether they're expecting degrees or radians...

For those looking for a powerful compile-time type-safe unit library, but are hesitant about dragging in a boost dependency, check out units. The library is implemented as a single .h file with no dependencies, and comes with a project to build unit tests/documentation. It's tested with msvc2013, 2015, and gcc-4.9.2, and should work with later versions of those compilers as well.

Full Disclosure: I'm the author of the library

Yes, it makes sense. Not only in physics, but in any discipline. In finance, e.g. interest rates are in units of inverse time intervals (typically express per year). Money has many different units. Converting between them can only be done with a cross-rate, has dimensions of one currency divided by another. Interest payments, dividend payments, principal payments, etc. ordinarily occur at a frequency.

It can prevent multiplying two values and ending up with an illegal value. It can prevent summing dollars and euros, etc.

I'm not saying you're wrong to do so, but we've gone overboard with that on the project I'm working on and frankly I doubt its benefits outweigh its hassle. Particularly if you're on a team, good variable naming (just spell the darn things out), code reviews, and unit testing will prevent any problems. On the other hand, if you can use Boost, units might be something to check into (I haven't).

To check for type safety, you can use a dedicated library.

The most wiedly use is boost::units, it works perfertly with no execution time overhead, a lot of features. If this library theoritically solve your problem. From a more practical point of vew, the interface is so awkward and badly documented that you may have problems. Morever the compilation time increase drastically with the number of dimensions, so clearly check that you can compile in a reasonable time a large project before using it.

doc : http://www.boost.org/doc/libs/1_56_0/doc/html/boost_units.html

An alternative is to use unit_lite. There are less features than the boost library but the compilation is faster, the interface simpler and errors messages are readables. This lib requires C++11.

code : https://github.com/pierreblavy2/unit_lite

The link to the doc is in the github description (I'm not allowed to post more than 2 links here !!!).

I gave a tutorial presentation at CPPcon 2015 on the Boost.Units library. It's a powerful library that every scientific application should be using. But it's hard to use due to poor documentation. Hopefully my tutorial helps with this. You can find the slides/code here:

If you want to use a very light weight header-only library based on c++20, you can use TU (Typesafe Units). It supports manipulation (*, /, +, -, sqrt, pow to arbitrary floating point numbers, unary operations on scalar units) for all SI units. It supports units with floating point dimensions like length^(d) where d is a decimal number. Moreover it is simple to define your own units. It also comes with a test suite...

...and yes, I'm the author of this library.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top