Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type safe physics operations in C++

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?

like image 658
Mircea Ispas Avatar asked Nov 11 '13 16:11

Mircea Ispas


4 Answers

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.

like image 122
Mike Seymour Avatar answered Sep 23 '22 13:09

Mike Seymour


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
like image 44
Viktor Sehr Avatar answered Sep 20 '22 13:09

Viktor Sehr


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.

like image 34
David Avatar answered Sep 23 '22 13:09

David


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

like image 31
BlueRaja - Danny Pflughoeft Avatar answered Sep 23 '22 13:09

BlueRaja - Danny Pflughoeft