Boost logo

Boost :

Subject: Re: [boost] [units] - learning to use, more questions :)
From: Matthias Schabel (boost_at_[hidden])
Date: 2011-11-28 17:13:55


> And I've hit a brick wall, because I cannot get those lines to compile:
>
> quantity<reciprocal_area> lambda ( 2.0*m*E / (hbar*hbar) );
> quantity<reciprocal_area> alpha ( m*omega/root<2>(hbar) );
> double lambda_per_alpha ( lambda / alpha );
>
> Even the first one has problems, to my surprise. Maybe I really
> should change my g++ 4.4.5 version to a newer version? I will gladly try
> this if you think it makes sense.

The first line compiles correctly using Boost 1.48; I don't know when the fix was made. The second line there is a bug/missing feature; the constants don't define pow/root operations, although I don't understand exactly why the implicit conversion to the appropriate quantity type is not working. We will fix that in the next release... For the interim, you can use root<2>(hbar.value()), although I recognize that it is somewhat confusing since, in this context, value() returns a quantity, not a value_type.

However, you also have an error in the second line; alpha is not a reciprocal_area : kg * (1/s) / (kg m^2/s)^1/2 = kg^1/2 s^-1/2 m^-1. Of course, this makes the third line incorrect as well; an example of the power of Boost.Units, I guess...

In general, when debugging units, it is often helpful to output to the console. Use of auto for intermediate values is also your friend... For example, here's what I did to figure out your problem:

#include <iostream>
#include <complex>
using namespace std;
//use units
#include <boost/typeof/std/complex.hpp>
#include <boost/units/cmath.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/systems/si/codata/universal_constants.hpp>

#include <boost/units/io.hpp>

using namespace boost::units;
using namespace boost::units::si;
using namespace boost::units::si::constants::codata;
//use units end

typedef derived_dimension<length_base_dimension,-2>::type reciprocal_area_dimension;
typedef unit<reciprocal_area_dimension,si::system> reciprocal_area;

int main()
{
        int n = 5;
        quantity<mass> m(1*kilogram);
        quantity<frequency> omega(1*hertz);
        quantity<energy> E(hbar*omega*(n+0.5));
        quantity<reciprocal_area> lambda(2.0*m*E/(hbar*hbar));
        
        std::cout << m << std::endl;
        std::cout << omega << std::endl;
            std::cout << E << std::endl;
            std::cout << lambda << std::endl;
// std::cout << m*omega/root<2>(hbar) << std::endl; // bug - this should work
        std::cout << m*omega/root<2>(hbar.value()) << std::endl; // works but shouldn't be necessary and bad choice of syntax
        
            return 0;
}

output :

1 kg
1 s^-1
5.80014e-34 m^2 kg s^-2
1.04308e+35 m^-2
9.73782e+16 m^-1 kg^(1/2) s^(-1/2)

Steven - since you implemented the constants.hpp header, I'm a little reluctant to rummage through it. Could you please consider

1) adding support for the pow<> and root<> operations?
2) deprecating constant.value_type and constant.value() in favor of constant.quantity_type and constant.quantity() or constant.mean_value() or constant.mean() or something?

Also, can you remind me why we have "constant" and "physical_constant" structs? They look identical to me...

Janek,

I have attached headers implementing the various prefixed short cuts for the meter and joule; these two should be sufficient to extend to the rest of the SI unit system. What remains to be done is to replicate scaled_meter.hpp/scaled_length.hpp for the remaining base units in the <boost/units/base_units/si> directory and to replicate scaled_energy.hpp for all the remaining named SI units in the <boost/units/systems/si> directory.

Here's my test program:

#include <iostream>

#include <boost/units/io.hpp>
#include <boost/units/systems/si/length.hpp>
#include <boost/units/systems/si/energy.hpp>

#include "scaled_length.hpp"

#include "scaled_energy.hpp"

using namespace boost::units;
using namespace boost::units::si;

int main()
{
        std::cout << 1.0*nm << "\t" << 1.5*mJ << std::endl;
        
        quantity<length> q1(1.0*nm);
        quantity<energy> q2(1.5*mJ);
        
        std::cout << q1 << "\t" << q2 << std::endl;

        auto q3(1.0*nm);
        auto q4(1.5*mJ);
        
        std::cout << q3 << "\t" << q4 << std::endl;
        
        return 0;
}

and output :

1 nm 1.5 mJ
1e-09 m 0.0015 m^2 kg s^-2
1 nm 1.5 mJ

Note: if you assign these scaled quantities to unscaled quantities, the scaling information will be lost (second output line)...

Matthias


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk