Posted: Apr 03, 2012 10:41 am
by epepke
VazScep wrote:Formally, the idea is that units of measure are just types in a free Abelian group generated by base units. Less pompously, you create a dimension type by stringing together base units and identifying types such as ms2s-1 and smm-1m.


This is reasonably easy to do in C++ by overloading the multiplication operator. I've done a units package based on this. A simple example:

Code: Select all
Distance d = 3 * Meter;


This is pretty useful.

There are a few problems, though.

1) Some units are funny, such as degrees Fahrenheit and Celsius, which requires an offset. The HDF system expressed units as a multiplier and an offset, which gets rid of this particular problem, though it cannot handle units that have, say, logarithms. Most of these problems can be kluged in C++ by overloading conversion functions.

2) It doesn't really distinguish very well between absolute and relative units. So, for example,

Code: Select all
2 * DegreesCelsius + 5 * DegreesCelsius[/quote]

will be understood by a person as meaning 7 degrees Fahrenheit, but that isn't obvious from the definition.  Still, that can be kluged reasonably well by overloading addition and subtraction.  You cannot just fix this by doing all calculation in, say, DegreesKelvin and converting back.

3) It doesn't easily handle all the conventions that people have.  For example,

[code]5 * Dollars + 20 * Percent


would be understood by a person as (5 * (1 + 0.20)) * Dollars. It isn't obvious how to do it, except by overloading + and -. To do it requires writing a lot of functions. I'd do this by writing some code in Perl to emit C++ code for all (expected) possibilities.

4) Getting an automatic type for a complex expression pretty much relies on the optimizations from the compiler. These vary. Also, for debugging, one sometimes has to drop to a lower level of optimization, which results in a lot of swearing.

5) Related to 4, the compiler cannot generally assume and Abelian group. For example, you might want to overload * for something like tensors, the multiplication of which is not commutative.

Still, it's pretty useful, and can avoid problems like that Mars lander that crashed because one unit was working in feet and another in meters. It can also be set either to do conversions automatically, for debugging, or a zero-cost deployment, producing compiler errors.