Boost logo

Boost :

Subject: Re: [boost] Units of data
From: Matthias Schabel (boost_at_[hidden])
Date: 2009-07-02 20:01:29


Just to be concrete, I've reworked your code a bit to eliminate
extraneous complexity :

#include <iostream>

#include <boost/units/base_dimension.hpp>
#include <boost/units/base_unit.hpp>
#include <boost/units/io.hpp>
#include <boost/units/scale.hpp>
#include <boost/units/scaled_base_unit.hpp>
#include <boost/units/make_system.hpp>
#include <boost/units/static_constant.hpp>
#include <boost/units/quantity.hpp>

#define DECLARE_BASE_UNIT_INFO(base_unit_, name_, symbol_) \
template<> struct base_unit_info<base_unit_> { \
        static const char* name() { return name_; } \
        static const char* symbol() { return symbol_; } \
};

namespace boost {

namespace units {

struct data_capacity_base_dimension :
base_dimension<data_capacity_base_dimension, 73254> {};
typedef data_capacity_base_dimension::dimension_type
data_capacity_dimension;

struct bit_base_unit :
base_unit<bit_base_unit,data_capacity_dimension, 76389> {};

typedef scaled_base_unit<bit_base_unit, scale<2, static_rational<3> >
> byte_base_unit;
typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<10>
> > kilobyte_base_unit;
typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<20>
> > megabyte_base_unit;
typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<30>
> > gigabyte_base_unit;
typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<40>
> > terabyte_base_unit;
typedef scaled_base_unit<byte_base_unit, scale<2, static_rational<50>
> > petabyte_base_unit;

DECLARE_BASE_UNIT_INFO(bit_base_unit, "bit", "b")
DECLARE_BASE_UNIT_INFO(byte_base_unit, "byte", "B")
DECLARE_BASE_UNIT_INFO(kilobyte_base_unit, "kilobyte", "KB")
DECLARE_BASE_UNIT_INFO(megabyte_base_unit, "megabyte", "MB")
DECLARE_BASE_UNIT_INFO(gigabyte_base_unit, "gigabyte", "GB")
DECLARE_BASE_UNIT_INFO(terabyte_base_unit, "terabyte", "TB")
DECLARE_BASE_UNIT_INFO(petabyte_base_unit, "petabyte", "PB")

BOOST_UNITS_STATIC_CONSTANT(bit, bit_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(bits, bit_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(byte, byte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(bytes, byte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(kilobyte, kilobyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(kilobytes, kilobyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(megabyte, megabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(megabytes, megabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(gigabyte, gigabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(gigabytes, gigabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(terabyte, terabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(terabytes, terabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(petabyte, petabyte_base_unit::unit_type);
BOOST_UNITS_STATIC_CONSTANT(petabytes, petabyte_base_unit::unit_type);

}
}

using namespace boost::units;

template<class U,class Y>
void outputDataCapacity(const quantity<U,Y>& q)
{
     static const Y bits_per_byte = 8,
                     bits_per_kilobyte = 8*1024,
                     bits_per_megabyte = 8*1024*1024,
                     bits_per_gigabyte = 8*1024*1024*1024;

     const quantity<bit_base_unit::unit_type,Y> qb(q);
     const Y qv(qb.value());

     if (qb.value() <= bits_per_byte)
         std::cout << qb << std::endl;
     else if (qb.value() <= bits_per_kilobyte)
         std::cout << quantity<byte_base_unit::unit_type,Y>(q) <<
std::endl;
     else if (qb.value() <= bits_per_megabyte)
         std::cout << quantity<kilobyte_base_unit::unit_type,Y>(q) <<
std::endl;
     else if (qb.value() <= bits_per_gigabyte)
         std::cout << quantity<megabyte_base_unit::unit_type,Y>(q) <<
std::endl;
     else
         std::cout << "error..." << std::endl;

     return;
}

int main()
{
        quantity<bit_base_unit::unit_type, int> c1(1000 * bits);
        quantity<byte_base_unit::unit_type, int> c2(1000 * bytes);
        quantity<kilobyte_base_unit::unit_type, int> c3(1000 * kilobytes);
        quantity<megabyte_base_unit::unit_type, int> c4(1000 * megabytes);

        quantity<bit_base_unit::unit_type, int> d1(1 * gigabyte);
        quantity<byte_base_unit::unit_type, int> d2(1 * gigabyte);
        quantity<kilobyte_base_unit::unit_type, int> d3(1 * gigabyte);
        quantity<megabyte_base_unit::unit_type, int> d4(1 * gigabyte);

     std::cout << c1 << std::endl;
     std::cout << c2 << std::endl;
     std::cout << c3 << std::endl;
     std::cout << c4 << std::endl;
     std::cout << std::endl;

     std::cout << d1 << std::endl;
     std::cout << d2 << std::endl;
     std::cout << d3 << std::endl;
     std::cout << d4 << std::endl;
     std::cout << std::endl;

     for (double v=1.0;v<=std::pow(2.0,24);v*=2.0)
     {
         outputDataCapacity(v*bits);
     }

     return 0;
}

This code compiles and runs correctly and does what you would expect,
outputting :

1000 b
1000 B
1000 KB
1000 MB

2147483647 b
1073741824 B
1048576 KB
1024 MB

1 b
2 b
4 b
8 b
2 B
4 B
8 B
16 B
32 B
64 B
128 B
256 B
512 B
1024 B
2 KB
4 KB
8 KB
16 KB
32 KB
64 KB
128 KB
256 KB
512 KB
1024 KB
error...

The conceptual problem that you're having is wanting the program to
somehow "know" that you want a quantity that is represented in bits to
be output as megabytes. However, while the program knows that those
units are convertible, there is no way for it to know that you want
megabytes instead of gigabytes, kilobytes, or any other unit for which
the conversion is defined. Thus, if you want specific output
formatting, you need to do it yourself like I've done in
outputDataCapacity...

Hope this helps.

Matthias


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