2
\$\begingroup\$

I'm trying to create some helper functions that will allow me to convert from one unit of measurement to another. I eventually will need to be able to do speeds and temperatures as well, but so far, I've only implemented lengths. I'm not using C++11 for this solution.

Here are my structs. My structs are basically wrappers around enums for type safety.

namespace MyNS
{
    struct MetricValue {
        enum MetricPrefixType
        {
            yocto = -24,
            zepto = -21,
            atto = -18,
            femto = -15,
            pico = -12,
            nano = -9,
            micro = -6,
            milli = -3,
            centi = -2,
            deci = -1,
            base = 0,
            deca = 1,
            hecto = 2,
            kilo = 3,
            mega = 6,
            giga = 9,
            tera = 12,
            peta = 15,
            exa = 18,
            zetta = 21,
            yotta = 24
        } type ;

        MetricValue (MetricPrefixType type = MetricPrefixType::base) : type (type)
        {
        }
    };

    struct ImperialLengthValue {
        enum ImperialLengthType
        {
            inch = 1,
            foot = 12,
            yard = 36,
            mile = 63360
        } type ;

        ImperialLengthValue (ImperialLengthType type = ImperialLengthType::inch) : type (type)
        {
        }
    };

} // end of namespace MyNS

Here are my functions. abs() and pow() are helper functions. My implementation of pow() is meant to handle negative powers properly.

namespace MyNS {
    template <typename T>
    T abs (T tVal) {
        return (tVal > 0) ? tVal : -tVal ;
    }

    double pow (double base, int power)
    {
        if (power == 0) {
            return 1 ;
        }

        if (power == 1) {
            return base ;
        }

        double dVal = base ;
        int absPower = MyNS::abs (power) ;

        for (int n = 1; n < absPower; ++n) {
            dVal *= base ;
        }

        if (power < 0) {
            dVal = 1 / dVal ;
        }

        return dVal ;
    }

    template <typename T>
    T ConvertLength (T tVal, MetricValue from, MetricValue to)
    {
        return static_cast <T> (tVal * MyNS::pow (10, from.type - to.type)) ;
    }

    template <typename T>
    T ConvertLength (T tVal, MetricValue from, ImperialLengthValue to)
    {
        // Convert to meters, then to inches, then to imperial type.
        return static_cast <T> (tVal * MyNS::pow (10, from.type) * 39.3701 / to.type) ;
    }

    template <typename T>
    T ConvertLength (T tVal, ImperialLengthValue from, MetricValue to)
    {
        // Convert to inches, then to meters, then to metric type.
        return static_cast <T> (tVal * from.type * 0.0254 / MyNS::pow (10, to.type)) ;
    }

    template <typename T>
    T ConvertLength (T tVal, ImperialLengthValue from, ImperialLengthValue to)
    {
        return static_cast <T> (tVal * from.type / to.type) ;
    }

} // end of namespace MyNS

Here is some example usage:

int main (void)
{
    typedef MyNS::MetricValue MetricValue ;
    typedef MyNS::ImperialLengthValue ImperialValue ;

    double d1 = MyNS::ConvertLength <double> (18000000, MetricValue (MetricValue::micro), MetricValue (MetricValue::deca)) ;
    double d2 = MyNS::ConvertLength <double> (0.5, MetricValue (MetricValue::kilo), MetricValue (MetricValue::milli)) ;

    double d3 = MyNS::ConvertLength <double> (500, MetricValue (MetricValue::centi), ImperialValue (ImperialValue::foot)) ;
    double d4 = MyNS::ConvertLength <double> (25, MetricValue (MetricValue::kilo), ImperialValue (ImperialValue::yard)) ;

    double d5 = MyNS::ConvertLength <double> (15500, ImperialValue (ImperialValue::foot), MetricValue (MetricValue::kilo)) ;
    double d6 = MyNS::ConvertLength <double> (0.5, ImperialValue (ImperialValue::mile), MetricValue (MetricValue::deci)) ;

    double d7 = MyNS::ConvertLength <double> (63500, ImperialValue (ImperialValue::inch), ImperialValue (ImperialValue::mile)) ;
    double d8 = MyNS::ConvertLength <double> (3, ImperialValue (ImperialValue::yard), ImperialValue (ImperialValue::foot)) ;

    return 0 ;
}
\$\endgroup\$
  • \$\begingroup\$ @GregHewgill Unless I'm misunderstanding your comment, there would not be a "zeptomile". \$\endgroup\$ – jliv902 May 23 '14 at 0:27
  • \$\begingroup\$ Related. \$\endgroup\$ – Jerry Coffin May 23 '14 at 1:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.