
Hi Ben,
I do think it would be great to distinguish between affine and vector spaces in a library like this, but in practical terms it seems like there are three levels of commitment that users might have to dimensional analysis: 1. Type of dimension (length versus temperature). 2. Units of measure (meters versus feet). 3. Absolute versus relative quantities (°C = K+273.15 versus °C = K).
The way I've developed the abstractions for this library is similar to the way you describe : 1) "raw" dimensional analysis as demonstrated in unit_example_1.cpp. This is purely compile-time metaprogramming, and is a little messy because of that. However, I suspect that this will be a relatively rare use case for end users of the library. Furthermore, if it turned out to be useful, it would certainly be possible to add some metaprogramming and/or preprocessor support to simplify the syntax and handling of dimensional analysis typelists. 2) units, defined as you do, a type of dimension with an associated unit system but no numeric value : SI::length, SI::energy, SI::power, etc... 3) quantities, defined as a quantity of a specified unit : 1.5*meters, (1.5+0.2*i)*ohms, etc... Quantities need to implement two algebras : the compile-time dimensional analysis algebra and the algebra for the underlying value_type. This is where handling of the difference between absolute and relative quantities would happen. The advantage of this is that I have already implemented quantity algebra in such a way that the value_type algebra should just delegate to the value_type itself (this requires typeof support or manual specialization of operator helpers for heterogeneous algebras), so the dimensional analysis is completely decoupled from the value_type algebra.
I'm thinking usage like this: // First: type of dimension quantity<double, distance> x1 = 42.0 * distance;
As it stands, the library assumes that quantities are values associated with a specific unit system. That being said, you can easily implement a unit system for "abstract" dimensioned quantities so you would write quantity<double,abstract::length> x1 = 42.0*abstract::length;
// Second: units of measure quantity<double, meters> x2 = 20.0 * meters;
This is basically identical to the existing SI system as implemented.
// Casting to explicitly add units of measure to unitless quantities. x2 = quantity_cast<quantity<double, meters> >(x1); // The user claims x1 is in meters.
This will hopefully be implemented for the next release.
// Allow casting a reference or pointer, too (important for interfacing with numerical solvers). quantity<double, meters>& xref = quantity_cast<quantity<double, meters>&>(x1); quantity<double, meters>* xptr = quantity_cast<quantity<double, meters>*>(x1);
This is a good idea; of course, since it involves pointers and references, I'm sure the actual implementation will be ugly to get constness and everything else right...
// Third, since most people won't want to get into this, let quantity be what // most would expect (i.e., a linear space) but add absolute_ and relative_ to be clear. absolute_quantity<double, temperature> t1 = 1000.0 * temperature; // Unspecified temperature type. absolute_quantity<double, temperature> t2 = 1010.0 * temperature;
relative_quantity<double, temperature> tdiff = t2 - t1; // tdiff is now 10 temperature units.
[snip] The way I'd propose to do this within the existing framework is to implement two different value_types: template<class Y> class absolute_measure; template<class Y> class difference_measure; with the appropriate algebra defined within and between the two classes (don't quote me on this - I'd need to think carefully about the exact algebra): absoute_measure - absolute_measure = difference_measure absolute_measure +- difference_measure = absolute_measure absolute_measure +*/ absolute_measure = error absolute_measure */ scalar = absolute_measure (?) difference_measure -> normal quantity algebra, implicitly convertible to value_type (Y) Then you would have quantity<absolute_measure<double>,SI::temperature> t1 = 1000.0*SI::kelvin, t2 = 1010.0*SI::kelvin; quantity<difference_measure<double>,SI::temperature> tdiff = t2-t1; quantity_casts would just work by delegating to the appropriate value_type constructor when converting explicitly between absolute_measure and relative_measure...
PS Temperature is particularly odd in that absolute temperature it is (almost) a linear space even though temperature differences are in a different linear space. That is, 0°C × 2 = 273.15K × 2 = 546.3K = 273.15°C. (I say "almost" because there's no negative absolute temperature, so it can't really be a linear space.)
I'm not sure I follow the significance here...
PPS Where can I find the code under discussion?
It's in the Boost Vault : http://www.boost-consulting.com/vault/index.php? &direction=0&order=&directory=Units file is mcs_units_v0.5.4.zip Thanks for the feedback. Matthias