Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Automatically Scaled Units

It is often desirable to scale a unit automatically, depending on its value, to keep the integral part in a limited range, usually between 1 and 999.

For example, using engineering notation prefixes,

"1234.5 m" is more helpfully displayed as "1.234 km"
"0.000000001234 m" is more clearly displayed as "1.2345 nanometer".

The iostream manipulators engineering_prefixes or binary_prefixes make this easy.

using boost::units::binary_prefix;
using boost::units::engineering_prefix;
using boost::units::no_prefix;

quantity<length> l = 2.345 * meters;   // A quantity of length, in units of meters.
cout << engineering_prefix << l << endl; // Outputs "2.345 m".
l =  1000.0 * l; // Increase it by 1000, so expect a k prefix.
// Note that a double 1000.0 is required - an integer will fail to compile.
cout << engineering_prefix << l << endl; // Output autoprefixed with k to "2.345 km".

quantity<energy> e = kilograms * pow<2>(l / seconds); // A quantity of energy.
cout << engineering_prefix << e << endl; // 5.49902 MJ
cout << name_format << engineering_prefix << e << endl; // 5.49902 megaJoule

(The complete set of engineering and scientific multiples is not used (not centi or deci for example), but only powers of ten that are multiples of three, 10^3).

Similarly, the equivalent binary prefixes used for displaying computing kilobytes, megabytes, gigabytes...

These are the 2^10 = 1024, 2^20 = 1 048 576, 2^30 ... multiples.

(See also Prefixes for binary multiples

This scale is specified in IEC 60027-2, Second edition, 2000-11, Letter symbols to be used in electrical technology - Part 2: Telecommunications and electronics).

// Don't forget that the units name or symbol format specification is persistent.
cout << symbol_format << endl; // Resets the format to the default symbol format.

quantity<byte_base_unit::unit_type> b = 2048. * byte_base_unit::unit_type();
cout << engineering_prefix << b << endl;  // 2.048 kb
cout << symbol_format << binary_prefix << b << endl; //  "2 Kib"

But note that scalar dimensionless values, like int, float and double, are not prefixed automatically by the engineering_prefix or binary_prefix iostream manipulators.

const double s1 = 2345.6;
const long x1 = 23456;
cout << engineering_prefix << s1 << endl; // 2345.6
cout << engineering_prefix << x1 << endl; // 23456

cout << binary_prefix << s1 << endl; // 2345.6
cout << binary_prefix << x1 << endl; // 23456

You can output the name or symbol of a unit (rather than the most common quantity of a unit).

const length L; // A unit of length (but not a quantity of length).
cout << L << endl; // Default length unit is meter,
// but default is symbol format so output is just "m".
cout << name_format << L << endl; // default length name is "meter".

Note too that all the formatting flags are persistent, so that if you set engineering_prefix, then it applies to all future outputs, until you select binary_prefix, or explicitly switch autoprefix off. You can specify no prefix (the default of course) in two ways:

no_prefix(cout); // Clear any prefix flag.
cout << no_prefix << endl; // Clear any prefix flag using `no_prefix` manipulator.

And you can get the format flags for diagnosing problems.

cout << boost::units::get_autoprefix(cout) << endl; // 8 is `autoprefix_binary` from `enum autoprefix_mode`.
cout << boost::units::get_format(cout) << endl; // 1 is `name_fmt` from `enum format_mode`.


PrevUpHomeNext