2

I'm trying to teach myself Boost Unit, but I am having some problems when it comes to using units as a float replacement.

  1. I'm using a custom dalton/amu unit for calculations. My old code works like

    float baseMass = 14.95;
    float totalMass = baseMass * 12;
    

    However, doing the same with units (dalton_t is a typedef of quantity)

    dalton_t baseMass = 14.95 * units::dalton_mass;
    dalton_t totalMass = baseMass * 12;
    

    provides an error "invalid operands to binary expression." Does this mean that 12 should be some sort of dimensionless unit?

  2. I also use the mass as a key in an unordered set.

    typedef boost::unordered_set<types::dalton_t> DaltonSet;
    DaltonSet dSet;
    dalton_t testMass(13384.384 * phobos::units::dalton_mass);
    dSet.insert(testMass);
    

    This provides an error "No matching function for call to hash_value", even though it is defined in the header file for units.

Any ideas for either of these?

The units header file is below:

#ifndef UNITS_H_
#define UNITS_H_
#include <boost/functional/hash.hpp>
#include <boost/units/conversion.hpp>
#include <boost/units/io.hpp>
#include <boost/units/pow.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/prefixes.hpp>

namespace phobos {


namespace units {
using boost::units::mass_dimension;
using boost::units::pow;
using boost::units::root;
using boost::units::quantity;
using boost::units::unit;

struct amu_mass_base_unit :
    boost::units::base_unit<amu_mass_base_unit, mass_dimension, 1> {
        static std::string name() { return "atomic mass unit"; }
        static std::string symbol() { return "u"; }
    };

    typedef boost::units::make_system<amu_mass_base_unit>::type amu_system;
    typedef unit<mass_dimension, amu_system> amu_mass;
    static const amu_mass dalton_mass;
} /* namespace units */

namespace types {
using boost::units::quantity;
typedef quantity<units::amu_mass, float> amu_t;
typedef amu_t dalton_t;
} /* namespace types */
} /* namespace phobos */

BOOST_UNITS_DEFINE_CONVERSION_FACTOR(phobos::units::amu_mass_base_unit,
        boost::units::si::kilogram_base_unit,
        float, 1.66053892173e-27);

std::size_t hash_value(const phobos::types::amu_t &amu) {
    return boost::hash_value(amu.value());
}

#endif /* UNITS_H_ */

Thank you in advance!

Adam

notwithoutend
  • 235
  • 1
  • 9

2 Answers2

2

Your first question scrapes a known weakness of Boost.Units: There is no type promotion in arithmetic expression, so the scalars must match the quantities' types. baseMass * 12.0f should work.

thiton
  • 35,651
  • 4
  • 70
  • 100
  • That makes sense. How much calculation degradation could I expect from the int->float conversions? Or slowdowns? Or does it happen anyway without me realizing? I admit I don't know much about the inner workings of x86_64 float mechanics. – notwithoutend Jun 20 '12 at 16:32
  • @notwithoutend: With normal C++ built-in types, this promotion happens anyway and internally. That Boost.Units doesn't do it is a bug. – thiton Jun 20 '12 at 17:22
  • Awesome. Thank you so much for your help. I don't suppose you have any ideas on the second question? – notwithoutend Jun 20 '12 at 18:16
1

As to the boost units not being hashable, I figured that out as well:

namespace std {
template <> struct hash<phobos::types::amu_t> {
    inline std::size_t operator()(const phobos::types::amu_t &amu) const {
        return std::hash<phobos::types::mass_store_t>()(amu.value());
    }
};
}
notwithoutend
  • 235
  • 1
  • 9