AMDG Manoj Rajagopalan wrote:
Hi boost::units developers
I am interested in extending the scale system for units. Here I present a short explanation, my initial hack to get this working, and questions on a small re-engineering issue that will crop up if this proposal is accepted.
*** WHY ***
Existing boost-units code allows scales which have factors as integral powers of a base, b^e, eg. 10^3, 2^10 etc. I'd like to use scales that have factors of the form a*b^e,
Examples: (a) electron-Volt (eV) = 1.602*10^{-19} J (b) bohr = 0.528 Angstroms = 5.28*10^{-11} m
In quantum chemistry, for example, such an "atomic units system" is typically used.
In this case it's probably easier to define a new
base unit and use the conversion macros, which
can accept a double. (Warning untested)
struct electron_volt_base_unit : base_unit
To achieve this using templates (which don't (yet) recognize floating point constants), I borrowed the idea from the 'dimnum' package. I, (1) added two more parameters of type long to the scale<> template which are the numerator and denominator of the rational approximation to a, (2) added static const value_type factor() member function which returns the value 'a' evaluated as double, (3) modified the value() static member to return factor() * b^e instead of simply b^e
--------------- Code snippet (scale.hpp):
template
struct scale { // ... static const double factor() { return double(FactorNumerator)/double(FactorDenominator); } static value_type value() { return(factor() * detail::static_rational_power<Exponent>(static_cast<double>(base))); } // ... }; ---------------- I modified the defintion of the apply<> template class in the boost::mpl::plus_impl, boost::mpl::negate_impl classes in unscale.hpp so that the scale<> return template-type now includes the correct FactorNumerator and FactorDenominator results based on the operands. This seems to be the place where arithmetic on scales is being performed for inter-conversion of quantities. I couldn't modify boost::mpl::times_impl because I'd have to statically exponentiate the numerator/denominator here and this doesn't fit cleanly into the existing mechanism.
You can do something like this by chaining scales together.
For example:
typedef scaled_base_unit
hour_base_unit; typedef scaled_base_unit
> day_base_unit; typedef scaled_base_unit > > week_base_unit;
*** WHAT ***
I do have the following questions/observations - please answer/comment.
1. The current implementation assumes that the scales being multiplied have the same base and differ only in the exponent? I just see T0::base being copied as the new base. This can be fixed with the generalized scale approach where if the bases are different (eg. 2 and 10), the resulting base is a default (10?) with exponent=static_rational<0,1> and a new factor f=(2^e1)*(10^e2). Of course, this will work only if there are no overflows.
The current implementation never multiplies scales that have different bases. In the implementation of conversions, scales are collected in a list sorted by base.
A conceivable use-case for this feature is when calculating, say, price-per-GB that is incurred in setting up a data-center. $<--->c interconversion will require 10^2 scale along the currency dimension while MB<--->GB<--->TB interconversions will require 2^10 scale along the memory dimension (assume they can be created). Here, currency interconversion will necessitate a generalized scale.
2. For simple scales like the existing one, multiplication of scales leads to addition of the exponents and therefore I can understand the static-overload of the plus_impl template to allow MPL to add the exponents. But with generalized scales we will have to switch to a different mechanism. Could you advise me on what all will need to be changed? I have a fair idea and I could use your input to cross-check.
3. When I complete this, can I submit the patch? I would like to add the atomic units system to the existing list of systems
In Christ, Steven Watanabe