1476 lines
62 KiB
Plaintext
1476 lines
62 KiB
Plaintext
[library Boost.Units
|
|
[quickbook 1.5]
|
|
[version 1.1.0]
|
|
[authors [Schabel, Matthias C.]]
|
|
[authors [Watanabe, Steven]]
|
|
[copyright 2003-2008 Matthias Christian Schabel, 2007-2010 Steven Watanabe]
|
|
[license
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
[@http://www.boost.org/LICENSE_1_0.txt])
|
|
]
|
|
[purpose zero-overhead compile-time dimensional analysis and unit computations]
|
|
]
|
|
|
|
[/ Some links to external sources.]
|
|
[def __boost [@http://www.boost.org/ Boost]]
|
|
[def __boostroot [@boost: Boost root]]
|
|
[def __boostlicense [@http://www.boost.org/LICENSE_1_0.txt Boost License]]
|
|
[def __boost_mpl [@http://www.boost.org/libs/mpl/doc/index.html Boost Metaprogramming Library]]
|
|
|
|
[def __mpl_forward_sequence [@http://www.boost.org/libs/mpl/doc/refmanual/forward-sequence.html MPL Forward Sequence]]
|
|
|
|
[/Links within this document.]
|
|
[def __ordinal [classref boost::units::ordinal ordinal]]
|
|
[def __dim [classref boost::units::dim dim]]
|
|
[def __static_rational [classref boost::units::static_rational static_rational]]
|
|
[def __make_dimension_list [classref boost::units::make_dimension_list make_dimension_list]]
|
|
[def __unit [classref boost::units::unit unit]]
|
|
[def __base_unit_info [classref boost::units::base_unit_info base_unit_info]]
|
|
[def __quantity [classref boost::units::quantity quantity]]
|
|
[def __conversion_helper [classref boost::units::conversion_helper conversion_helper]]
|
|
[def __absolute [classref boost::units::absolute absolute]]
|
|
[def __base_unit [classref boost::units::base_unit base_unit]]
|
|
[def __base_dimension [classref boost::units::base_dimension base_dimension]]
|
|
[def __scaled_base_unit [classref boost::units::scaled_base_unit base_unit]]
|
|
[def __make_scaled_unit [classref boost::units::make_scaled_unit make_scaled_unit]]
|
|
|
|
[def __unary_plus_typeof_helper [classref boost::units::unary_plus_typeof_helper unary_plus_typeof_helper]]
|
|
[def __unary_minus_typeof_helper [classref boost::units::unary_minus_typeof_helper unary_minus_typeof_helper]]
|
|
[def __add_typeof_helper [classref boost::units::add_typeof_helper add_typeof_helper]]
|
|
[def __subtract_typeof_helper [classref boost::units::subtract_typeof_helper subtract_typeof_helper]]
|
|
[def __multiply_typeof_helper [classref boost::units::multiply_typeof_helper multiply_typeof_helper]]
|
|
[def __divide_typeof_helper [classref boost::units::divide_typeof_helper divide_typeof_helper]]
|
|
[def __power_typeof_helper [classref boost::units::power_typeof_helper power_typeof_helper]]
|
|
[def __root_typeof_helper [classref boost::units::root_typeof_helper root_typeof_helper]]
|
|
|
|
[def __static_negate [classref boost::units::static_negate static_negate]]
|
|
[def __static_add [classref boost::units::static_add static_add]]
|
|
[def __static_subtract [classref boost::units::static_subtract static_subtract]]
|
|
[def __static_multiply [classref boost::units::static_multiply static_multiply]]
|
|
[def __static_divide [classref boost::units::static_divide static_divide]]
|
|
[def __static_power [classref boost::units::static_power static_power]]
|
|
[def __static_root [classref boost::units::static_root static_root]]
|
|
|
|
[def __get_dimension [classref boost::units::get_dimension get_dimension]]
|
|
[def __get_system [classref boost::units::get_system get_system]]
|
|
|
|
[def __pow [funcref boost::units::pow pow]]
|
|
[def __root [funcref boost::units::root root]]
|
|
[def __quantity_cast [funcref boost::units::quantity_cast quantity_cast]]
|
|
|
|
[def __from_value [memberref boost::units::quantity::from_value from_value]]
|
|
[def __value [memberref boost::units::quantity::value value]]
|
|
|
|
[def __reduce_unit [classref boost::units::reduce_unit reduce_unit]]
|
|
[def __unscale [classref boost::units::unscale unscale]]
|
|
|
|
[def __BOOST_UNITS_STATIC_CONSTANT [macroref BOOST_UNITS_STATIC_CONSTANT]]
|
|
[def __BOOST_UNITS_DEFINE_CONVERSION_FACTOR [macroref BOOST_UNITS_DEFINE_CONVERSION_FACTOR]]
|
|
[def __BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE [macroref BOOST_UNITS_DEFINE_CONVERSION_FACTOR_TEMPLATE]]
|
|
[def __BOOST_UNITS_DEFAULT_CONVERSION [macroref BOOST_UNITS_DEFAULT_CONVERSION]]
|
|
|
|
[section:Introduction Introduction]
|
|
|
|
The Boost.Units library is a C++ implementation of dimensional analysis in a general
|
|
and extensible manner, treating it as a generic compile-time metaprogramming problem. With appropriate
|
|
compiler optimization, no runtime execution cost is introduced, facilitating the use of this library to
|
|
provide dimension checking in performance-critical code. Support for units
|
|
and quantities (defined as a unit and associated value) for arbitrary unit system models and arbitrary
|
|
value types is provided, as is a fine-grained general facility for unit conversions. Complete SI and CGS unit
|
|
systems are provided, along with systems for
|
|
angles measured in degrees, radians, gradians, and revolutions and
|
|
systems for temperatures measured in Kelvin, degrees Celsius and degrees Fahrenheit.
|
|
The library architecture has been designed with flexibility and extensibility in mind; demonstrations of the ease
|
|
of adding new units and unit conversions are provided in the examples.
|
|
|
|
In order to enable complex compile-time dimensional analysis calculations with no runtime overhead,
|
|
Boost.Units relies heavily on the [___boost_mpl] (MPL) and on template metaprogramming techniques, and is, as a consequence,
|
|
fairly demanding of compiler compliance to ISO standards. At present, it has been successfully
|
|
compiled and tested on the following compilers/platforms :
|
|
|
|
# g++ 4.0.1 on Mac OSX 10.4
|
|
# Intel CC 9.1, 10.0, and 10.1 on Mac OSX 10.4
|
|
# g++ 3.4.4, 4.2.3, and 4.3.0 on Windows XP
|
|
# Microsoft Visual C++ 7.1, 8.0, and 9.0 on Windows XP
|
|
# Comeau 4.3.10.1 beta2 on Windows XP
|
|
# Metrowerks CodeWarrior 9.2 on Windows XP.
|
|
# Sun CC 5.9 on Solaris and Linux
|
|
|
|
The following compilers/platforms are known *not* to work :
|
|
|
|
# g++ 3.3.x
|
|
# Microsoft Visual C++ 6.0 on Windows XP
|
|
# Microsoft Visual C++ 7.0 on Windows XP
|
|
# Metrowerks CodeWarrior 8.0 on Windows XP.
|
|
# All versions of Borland.
|
|
|
|
[endsect]
|
|
|
|
[section:Quick_Start Quick Start]
|
|
|
|
Before discussing the basics of the library, we first define a few terms that will be used frequently
|
|
in the following :
|
|
|
|
* *Base dimension* : A base dimension is loosely defined as a measurable entity of interest; in conventional
|
|
dimensional analysis, base dimensions include length (\[L\]), mass (\[M\]), time (\[T\]), etc... but there is
|
|
no specific restriction on what base dimensions can be used. Base dimensions are essentially a tag type and
|
|
provide no dimensional analysis functionality themselves.
|
|
* *Dimension* : A collection of zero or more base dimensions, each
|
|
potentially raised to a different rational power.
|
|
For example, length = \[L\]^1, area = \[L\]^2, velocity = \[L\]^1/\[T\]^1, and
|
|
energy = \[M\]^1 \[L\]^2/\[T\]^2 are all dimensions.
|
|
* *Base unit* : A base unit represents a specific measure of a dimension. For example, while length is an abstract measure of
|
|
distance, the meter is a concrete base unit of distance. Conversions are defined using base units.
|
|
Much like base dimensions, base units are a tag type used solely to define units and do not support dimensional
|
|
analysis algebra.
|
|
* *Unit* : A set of base units raised to rational exponents, e.g. m^1, kg^1, m^1/s^2.
|
|
* *System* : A unit system is a collection of base units representing all the measurable entities of interest for a
|
|
specific problem. For example, the SI unit system defines seven base units : length (\[L\]) in meters,
|
|
mass (\[M\]) in kilograms, time (\[T\]) in seconds, current (\[I\]) in amperes, temperature (\[theta\]) in kelvin,
|
|
amount (\[N\]) in moles, and luminous intensity (\[J\]) in candelas. All measurable entities within the SI system can
|
|
be represented as products of various integer or rational powers of these seven base units.
|
|
* *Quantity* : A quantity represents a concrete amount of a unit. Thus, while the meter is the base
|
|
unit of length in the SI system, 5.5 meters is a quantity of length in that system.
|
|
|
|
To begin, we present two short tutorials. [@../../libs/units/tutorial/tutorial_1.cpp Tutorial1] demonstrates the use of
|
|
[@http://en.wikipedia.org/wiki/SI_units SI] units. After including the appropriate system headers
|
|
and the headers for the various SI units we will need (all SI units can be included with
|
|
[headerref boost/units/systems/si.hpp]) and for quantity I/O ([headerref boost/units/io.hpp]), we define
|
|
a function that computes the work, in joules, done by exerting a force in newtons over a specified distance in meters
|
|
and outputs the result to `std::cout`. The [___quantity] class accepts a second template parameter as its value type;
|
|
this parameter defaults to
|
|
`double` if not otherwise specified. To demonstrate the ease of using user-defined types in dimensional
|
|
calculations, we also present code for computing the complex impedance using `std::complex<double>`
|
|
as the value type :
|
|
|
|
[import ../example/tutorial.cpp]
|
|
|
|
[tutorial_code]
|
|
|
|
The intent and function of the above code should be obvious; the output produced is :
|
|
|
|
[tutorial_output]
|
|
|
|
While this library attempts to make simple dimensional computations easy to code, it is in no way
|
|
tied to any particular unit system (SI or otherwise). Instead, it provides a highly flexible compile-time
|
|
system for dimensional analysis, supporting arbitrary collections of base dimensions, rational
|
|
powers of units, and explicit quantity conversions. It accomplishes all of this via template metaprogramming techniques.
|
|
With modern optimizing compilers, this results in zero runtime overhead for quantity computations relative to the
|
|
same code without unit checking.
|
|
|
|
[endsect]
|
|
|
|
[section:Dimensional_Analysis Dimensional Analysis]
|
|
|
|
The concept of
|
|
[@http://en.wikipedia.org/wiki/Dimensional_analysis dimensional analysis]
|
|
is normally presented early on in introductory physics and engineering classes as a means of determining the
|
|
correctness of an equation or computation by propagating the physical measurement
|
|
[@http://en.wikipedia.org/wiki/Units_of_measurement units]
|
|
of various quantities through the equation along with their numerical values. There are a number of standard
|
|
unit systems in common use, the most prominent of which is the
|
|
[@http://en.wikipedia.org/wiki/SI_units Systeme International]
|
|
(also known as SI or MKS (meter-kilogram-second), which was a metric predecessor to the SI system named
|
|
for three of the base units on which the system is based). The SI
|
|
is the only official international standard unit system and is widely utilized in science and engineering.
|
|
Other common systems include the [@http://en.wikipedia.org/wiki/Cgs_units CGS]
|
|
(centimeter-gram-second) system and the
|
|
[@http://en.wikipedia.org/wiki/English_units English]
|
|
system still in use in some problem domains in the United States and elsewhere. In physics,
|
|
there also exist a number of other systems that are in common use in specialized subdisciplines. These are
|
|
collectively referred to as [@http://en.wikipedia.org/wiki/Natural_units natural units]. When
|
|
quantities representing different measurables are combined, dimensional analysis provides the means of
|
|
assessing the consistency of the resulting calculation. For example, the sum of two lengths is also a length,
|
|
while the product of two lengths is an area, and the sum of a length and an area is undefined. The fact that the
|
|
arguments to many functions (such as exp, log, etc...) must be dimensionless quantities can be easily demonstrated by
|
|
examining their series expansions in the context of dimensional analysis. This library facilitates the enforcement
|
|
of this type of restriction in code involving dimensioned quantities where appropriate.
|
|
|
|
In the following discussion we view dimensional analysis as an abstraction in which an arbitrary set of
|
|
[@http://en.wikipedia.org/wiki/Fundamental_units units] obey the rules of a specific algebra.
|
|
We will refer to a pair of a base dimension and a rational exponent as a *fundamental dimension*,
|
|
and a list composed of an arbitrary number of fundamental dimensions as a *composite dimension* or, simply,
|
|
*dimension*. In particular, given a set of [$../../libs/units/images/form_0.png] fundamental dimensions
|
|
denoted by [$../../libs/units/images/form_1.png] and a set of [$../../libs/units/images/form_0.png]
|
|
rational exponents [$../../libs/units/images/form_2.png], any possible (composite) dimension can be written
|
|
as [$../../libs/units/images/form_3.png].
|
|
|
|
Composite dimensions obey the algebraic rules for dimensional analysis. In particular, for any scalar value,
|
|
[$../../libs/units/images/form_4.png],
|
|
and composite dimensions [$../../libs/units/images/form_5.png]
|
|
and [$../../libs/units/images/form_6.png], where
|
|
[$../../libs/units/images/form_7.png], we have:
|
|
|
|
[$../../libs/units/images/form_8.png]
|
|
|
|
Users of a dimensional analysis library should be able to specify an arbitrary list of base dimensions to
|
|
produce a composite dimension. This potentially includes repeated tags. For example,
|
|
it should be possible to express energy as [$../../libs/units/images/form_9.png], [$../../libs/units/images/form_10.png],
|
|
[$../../libs/units/images/form_11.png], or any other permutation of mass, length, and time having aggregate exponents of
|
|
1, 2, and -2, respectively.
|
|
In order to be able to perform computations on arbitrary sets of dimensions,
|
|
all composite dimensions must be reducible to an unambiguous final composite dimension, which we will refer to as a
|
|
*reduced dimension*, for which
|
|
|
|
# fundamental dimensions are consistently ordered
|
|
# dimensions with zero exponent are elided. Note that reduced dimensions never have more than
|
|
[$../../libs/units/images/form_0.png] base dimensions, one for each distinct fundamental dimension, but may have fewer.
|
|
|
|
In our implementation, base dimensions are associated with tag types. As we will ultimately
|
|
represent composite dimensions as typelists, we must provide some mechanism for sorting
|
|
base dimension tags in order to make it possible to convert an arbitrary composite dimension
|
|
into a reduced dimension. For this purpose, we assign a unique integer to each base dimension.
|
|
The [___base_dimension] class (found in [headerref boost/units/base_dimension.hpp]) uses the
|
|
curiously recurring template pattern (CRTP) technique to ensure that ordinals specified for
|
|
base dimensions are unique:
|
|
|
|
template<class Derived, long N> struct base_dimension { ... };
|
|
|
|
With this, we can define the base dimensions for length, mass, and time as:
|
|
|
|
[import ../example/test_system.hpp]
|
|
[test_system_snippet_1]
|
|
|
|
It is important to note that the choice of order is completely arbitrary as long as each tag has a unique enumerable
|
|
value; non-unique ordinals are flagged as errors at compile-time. Negative ordinals are reserved for use by the library.
|
|
To define composite dimensions corresponding to the base dimensions, we
|
|
simply create MPL-conformant typelists of fundamental dimensions by using the [___dim] class to encapsulate pairs of base dimensions
|
|
and [___static_rational] exponents. The [___make_dimension_list] class acts as a wrapper to ensure
|
|
that the resulting type is in the form of a reduced dimension:
|
|
|
|
[test_system_snippet_2]
|
|
|
|
This can also be easily accomplished using a convenience typedef provided by [___base_dimension]:
|
|
|
|
[test_system_snippet_3]
|
|
|
|
so that the above code is identical to the full typelist definition. Composite dimensions are similarly defined via a typelist:
|
|
|
|
[test_system_snippet_4]
|
|
|
|
A convenience class for composite dimensions with integer powers is also provided:
|
|
|
|
[test_system_snippet_5]
|
|
|
|
[endsect]
|
|
|
|
[section:Units Units]
|
|
|
|
We define a *unit* as a set of base units each of which can be raised to an arbitrary rational
|
|
exponent. Thus, the SI unit corresponding to the dimension of force is kg m s^-2, where kg, m,
|
|
and s are base units. We use the notion of a *unit system* such as SI to specify the mapping
|
|
from a dimension to a particular unit so that instead of specifying the base units explicitly,
|
|
we can just ask for the representation of a dimension in a particular system.
|
|
|
|
Units are, like dimensions, purely compile-time variables with no associated value.
|
|
Units obey the same algebra as dimensions do; the presence of the unit system serves to ensure that units having identical
|
|
reduced dimension in different systems (like feet and meters) cannot be inadvertently mixed in computations.
|
|
|
|
There are two distinct types of systems that can be envisioned:
|
|
|
|
* *Homogeneous systems* : Systems which hold a linearly independent set of base units which
|
|
can be used to represent many different dimensions. For example, the SI system has seven
|
|
base dimensions and seven base units corresponding to them. It can represent any unit which
|
|
uses only those seven base dimensions. Thus it is a homogeneous_system.
|
|
* *Heterogeneous systems* : Systems which store the exponents of every base unit involved
|
|
are termed heterogeneous. Some units can only be represented in this way. For example,
|
|
area in m ft is intrinsically heterogeneous, because the base units of meters and feet
|
|
have identical dimensions. As a result, simply storing a dimension and a set of base
|
|
units does not yield a unique solution. A practical example of the need for heterogeneous
|
|
units, is an empirical equation used in aviation: H = (r/C)^2 where H is the radar beam
|
|
height in feet and r is the radar range in nautical miles. In order to enforce dimensional
|
|
correctness of this equation, the constant, C, must be expressed in nautical miles per foot^(1/2),
|
|
mixing two distinct base units of length.
|
|
|
|
Units are implemented by the [___unit] template class defined in [headerref boost/units/unit.hpp] :
|
|
|
|
template<class Dim,class System> class unit;
|
|
|
|
In addition to supporting the compile-time dimensional analysis operations, the +, -, *, and / runtime operators are provided
|
|
for [___unit] variables. Because the dimension associated with powers and roots must be computed at compile-time, it is not
|
|
possible to provide overloads for `std::pow` that function correctly for [___unit]s. These operations are supported through
|
|
free functions [___pow] and [___root] that are templated on integer and [___static_rational] values and can take as an argument
|
|
any type for which the utility classes [___power_typeof_helper] and [___root_typeof_helper] have been defined.
|
|
|
|
[section Base Units]
|
|
|
|
Base units are defined much like base dimensions.
|
|
|
|
template<class Derived, class Dimensions, long N> struct base_unit { ... };
|
|
|
|
Again negative ordinals are reserved.
|
|
|
|
As an example, in the following we will implement a subset of the SI unit system based on the fundamental dimensions
|
|
given above, demonstrating all steps necessary for a completely functional system. First, we simply define a unit system
|
|
that includes type definitions for commonly used units:
|
|
|
|
[test_system_snippet_6]
|
|
|
|
The macro [___BOOST_UNITS_STATIC_CONSTANT] is provided in [headerref boost/units/static_constant.hpp]
|
|
to facilitate ODR- and thread-safe constant definition in header files. We then define some constants for the supported units
|
|
to simplify variable definitions:
|
|
|
|
[test_system_snippet_7]
|
|
|
|
If support for textual output of units is desired, we can also specialize the [___base_unit_info] class for each fundamental
|
|
dimension tag:
|
|
|
|
[test_system_snippet_8]
|
|
|
|
and similarly for `kilogram_base_unit` and `second_base_unit`. A future version of the library will provide a more flexible system
|
|
allowing for internationalization through a facet/locale-type mechanism.
|
|
The `name()` and `symbol()` methods of [___base_unit_info] provide full and short names for the base unit. With these definitions,
|
|
we have the rudimentary beginnings of our unit system, which can be used to determine reduced dimensions for arbitrary
|
|
unit calculations.
|
|
|
|
[endsect] [/section Base Units]
|
|
|
|
[section Scaled Base Units]
|
|
|
|
Now, it is also possible to define a base unit as being a multiple of
|
|
another base unit. For example, the way that `kilogram_base_unit` is
|
|
actually defined by the library is along the following lines
|
|
|
|
struct gram_base_unit : boost::units::base_unit<gram_base_unit, mass_dimension, 1> {};
|
|
typedef scaled_base_unit<gram_base_unit, scale<10, static_rational<3> > > kilogram_base_unit;
|
|
|
|
This basically defines a kilogram as being 10^3 times a gram.
|
|
|
|
There are several advantages to this approach.
|
|
|
|
* It reflects the real meaning of these units better than treating them as independent units.
|
|
* If a conversion is defined between grams or kilograms and some other units,
|
|
it will automatically work for both kilograms and grams, with only one specialization.
|
|
* Similarly, if the symbol for grams is defined as "g", then the symbol for kilograms
|
|
will be "kg" without any extra effort.
|
|
|
|
[endsect] [/section Scaled Base Units]
|
|
|
|
[section Scaled Units]
|
|
|
|
We can also scale a [___unit] as a whole, rather than scaling the individual
|
|
base units which comprise it. For this purpose, we use the metafunction
|
|
[___make_scaled_unit]. The main motivation for this feature is the metric
|
|
prefixes defined in [headerref boost/units/systems/si/prefixes.hpp].
|
|
|
|
A simple example of its usage would be.
|
|
|
|
typedef make_scaled_unit<si::time, scale<10, static_rational<-9> > >::type nanosecond;
|
|
|
|
nanosecond is a specialization of [___unit], and can be used in a quantity normally.
|
|
|
|
quantity<nanosecond> t(1.0 * si::seconds);
|
|
std::cout << t << std::endl; // prints 1e9 ns
|
|
|
|
[endsect] [/section Scaled Units]
|
|
|
|
[endsect] [/section:Units Units]
|
|
|
|
[section:Quantities Quantities]
|
|
|
|
A *quantity* is defined as a value of an arbitrary value type that is associated with a specific unit. For example,
|
|
while meter is a unit, 3.0 meters is a quantity. Quantities obey two separate algebras: the native algebra for their
|
|
value type, and the dimensional analysis algebra for the associated unit. In addition, algebraic operations are defined
|
|
between units and quantities to simplify the definition of quantities; it is effectively equivalent to algebra with
|
|
a unit-valued quantity.
|
|
|
|
Quantities are implemented by the [___quantity] template class defined in [headerref boost/units/quantity.hpp] :
|
|
|
|
template<class Unit,class Y = double> class quantity;
|
|
|
|
This class is templated on both unit type (`Unit`) and value type (`Y`), with the latter defaulting to double-precision
|
|
floating point if not otherwise specified. The value type must have a normal copy constructor and copy
|
|
assignment operator. Operators +, -, *, and / are provided for algebraic operations between
|
|
scalars and units, scalars and quantities, units and quantities, and between quantities. In addition, integral and
|
|
rational powers and roots can be computed using the [___pow]<R> and [___root]<R> functions. Finally,
|
|
the standard set of boolean comparison operators ( `==, !=, <, <=, >, and >=` ) are provided to allow
|
|
comparison of quantities from the same unit system. All operators simply delegate to the
|
|
corresponding operator of the value type if the units permit.
|
|
|
|
[section:Heterogeneous_Operators Heterogeneous Operators]
|
|
|
|
For most common value types, the result type of arithmetic operators is the same as the value type itself. For example,
|
|
the sum of two double precision floating point numbers is another double precision floating point number. However, there
|
|
are instances where this is not the case. A simple example is given by the [@http://en.wikipedia.org/wiki/Natural_number
|
|
natural numbers] where the operator arithmetic obeys the following rules (using the standard notation for
|
|
[@http://en.wikipedia.org/wiki/Number number systems]):
|
|
|
|
* [$../../libs/units/images/form_12.png]
|
|
* [$../../libs/units/images/form_13.png]
|
|
* [$../../libs/units/images/form_14.png]
|
|
* [$../../libs/units/images/form_15.png]
|
|
|
|
This library is designed to support arbitrary value type algebra for addition, subtraction, multiplication, division, and
|
|
rational powers and roots. It uses Boost.Typeof to deduce the result of these operators. For compilers that
|
|
support `typeof`, the appropriate value type will be automatically deduced. For compilers that do not provide
|
|
language support for `typeof` it is necessary to register all the types used. For the case of natural numbers,
|
|
this would amount to something like the following:
|
|
|
|
BOOST_TYPEOF_REGISTER_TYPE(natural);
|
|
BOOST_TYPEOF_REGISTER_TYPE(integer);
|
|
BOOST_TYPEOF_REGISTER_TYPE(rational);
|
|
|
|
[endsect]
|
|
|
|
[section:Conversions Conversions]
|
|
|
|
Conversion is only meaningful for quantities as it implies the presence of at
|
|
least a multiplicative scale factor and, possibly, and affine linear offset.
|
|
Macros for simplifying the definition of conversions between units can be found in
|
|
[headerref boost/units/conversion.hpp] and [headerref boost/units/absolute.hpp]
|
|
(for affine conversions with offsets).
|
|
|
|
The macro [___BOOST_UNITS_DEFINE_CONVERSION_FACTOR] specifies a scale
|
|
factor for conversion from the first unit type to the second. The
|
|
first argument must be a [___base_unit]. The second argument
|
|
can be either a [___base_unit] or a [___unit].
|
|
|
|
Let's declare a simple base unit:
|
|
|
|
struct foot_base_unit : base_unit<foot_base_unit, length_dimension, 10> { };
|
|
|
|
Now, we want to be able to convert feet to meters and vice versa. The foot
|
|
is defined as exactly 0.3048 meters, so we can write the following
|
|
|
|
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(foot_base_unit, meter_base_unit, double, 0.3048);
|
|
|
|
Alternately, we could use the SI length `typedef`:
|
|
|
|
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(foot_base_unit, SI::length, double, 0.3048);
|
|
|
|
Since the SI unit of length is the meter, these two definitions are equivalent.
|
|
If these conversions have been defined, then converting between
|
|
scaled forms of these units will also automatically work.
|
|
|
|
The macro [___BOOST_UNITS_DEFAULT_CONVERSION] specifies a conversion
|
|
that will be applied to a base unit when no direct conversion is
|
|
possible. This can be used to make arbitrary conversions work
|
|
with a single specialization:
|
|
|
|
struct my_unit_tag : boost::units::base_unit<my_unit_tag, boost::units::force_type, 1> {};
|
|
// define the conversion factor
|
|
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(my_unit_tag, SI::force, double, 3.14159265358979323846);
|
|
// make conversion to SI the default.
|
|
BOOST_UNITS_DEFAULT_CONVERSION(my_unit_tag, SI::force);
|
|
|
|
[endsect]
|
|
|
|
[section:Quantity_Construction_and_Conversion Construction and Conversion of Quantities]
|
|
|
|
This library is designed to emphasize safety above convenience when performing operations with dimensioned quantities.
|
|
Specifically, construction of quantities is required to fully specify both value and unit. Direct construction from a scalar value
|
|
is prohibited (though the static member function [___from_value] is provided to enable
|
|
this functionality where it is necessary. In addition, a [___quantity_cast] to a reference allows direct access to the
|
|
underlying value of a [___quantity] variable. An explicit constructor is provided to enable conversion between
|
|
dimensionally compatible quantities in different unit systems. Implicit conversions between unit systems are
|
|
allowed only when the reduced units are identical, allowing, for example, trivial conversions between
|
|
equivalent units in different systems (such as SI seconds and CGS seconds) while simultaneously enabling
|
|
unintentional unit system mismatches to be caught at compile time and preventing potential loss of precision and
|
|
performance overhead from unintended conversions. Assignment follows the same rules.
|
|
An exception is made for quantities for which the unit reduces to dimensionless; in this case, implicit conversion
|
|
to the underlying value type is allowed via class template specialization. Quantities of different value types are implicitly
|
|
convertible only if the value types are themselves implicitly convertible. The [___quantity] class also defines
|
|
a `value()` member for directly accessing the underlying value.
|
|
|
|
To summarize, conversions are allowed under the following conditions :
|
|
|
|
* implicit conversion of `quantity<Unit,Y>` to `quantity<Unit,Z>` is allowed if `Y` and `Z` are implicitly convertible.
|
|
* assignment between `quantity<Unit,Y>` and `quantity<Unit,Z>` is allowed if `Y` and `Z` are implicitly convertible.
|
|
* explicit conversion between `quantity<Unit1,Y>` and `quantity<Unit2,Z>` is allowed if `Unit1` and `Unit2` have the same dimensions
|
|
and if `Y` and `Z` are implicitly convertible.
|
|
* implicit conversion between `quantity<Unit1,Y>` and `quantity<Unit2,Z>` is allowed if `Unit1`
|
|
reduces to exactly the same combination of base units as `Unit2` and if `Y` and `Z` are convertible.
|
|
* assignment between `quantity<Unit1,Y>` and `quantity<Unit2,Z>` is allowed under the same
|
|
conditions as implicit conversion.
|
|
* `quantity<Unit,Y>` can be directly constructed from a value of type `Y` using the static member function [___from_value]. Doing so,
|
|
naturally, bypasses any type-checking of the newly assigned value, so this method should be used only when absolutely necessary.
|
|
|
|
Of course, any time implicit conversion is allowed, an explicit conversion is
|
|
also legal.
|
|
|
|
Because dimensionless quantities have no associated units, they behave as normal scalars, and allow implicit conversion to and from
|
|
the underlying value type or types that are convertible to/from that value type.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:Examples Examples]
|
|
|
|
[section:DimensionExample Dimension Example]
|
|
|
|
([@../../libs/units/example/dimension.cpp dimension.cpp])
|
|
|
|
By using MPL metafunctions and the template specializations for operations on composite dimensions
|
|
(defined in [headerref boost/units/dimension.hpp]) it is possible to perform compile time arithmetic
|
|
according to the dimensional analysis rules described [link boost_units.Dimensional_Analysis above]
|
|
to produce new composite dimensions :
|
|
|
|
[import ../example/dimension.cpp]
|
|
|
|
[dimension_snippet_1]
|
|
|
|
outputting (with symbol demangling, implemented in
|
|
[@boost:/boost/units/detail/utility.hpp utility.hpp])
|
|
|
|
[dimension_output]
|
|
|
|
[endsect]
|
|
|
|
[section:UnitExample Unit Example]
|
|
|
|
([@../../libs/units/example/unit.cpp unit.cpp])
|
|
|
|
This example demonstrates the use of the simple but functional unit system implemented in
|
|
[@boost:/libs/units/example/test_system.hpp test_system.hpp]
|
|
|
|
[import ../example/unit.cpp]
|
|
|
|
[unit_snippet_1]
|
|
|
|
We can perform various algebraic operations on these units, resulting in the following output:
|
|
|
|
[unit_output]
|
|
|
|
[endsect]
|
|
|
|
[section:QuantityExample Quantity Example]
|
|
|
|
([@../../libs/units/example/quantity.cpp quantity.cpp])
|
|
|
|
This example demonstrates how to use quantities of our toy unit system :
|
|
|
|
[import ../example/quantity.cpp]
|
|
|
|
[quantity_snippet_1]
|
|
|
|
giving us the basic quantity functionality :
|
|
|
|
[quantity_output_double]
|
|
|
|
As a further demonstration of the flexibility of the system, we replace the `double` value type
|
|
with a `std::complex<double>` value type (ignoring the question of the meaningfulness of
|
|
complex lengths and energies) :
|
|
|
|
[quantity_snippet_2]
|
|
|
|
and find that the code functions exactly as expected with no additional work, delegating operations
|
|
to `std::complex<double>` and performing the appropriate dimensional analysis :
|
|
|
|
[quantity_output_complex]
|
|
|
|
[endsect]
|
|
|
|
[section:KitchenSinkExample Kitchen Sink Example using SI units]
|
|
|
|
([@../../libs/units/example/kitchen_sink.cpp kitchen_sink.cpp])
|
|
|
|
This example provides a fairly extensive set of tests covering most of the [___quantity] functionality.
|
|
It uses the SI unit system defined in [headerref boost/units/systems/si.hpp].
|
|
|
|
If we define a few units and associated quantities,
|
|
|
|
[import ../example/kitchen_sink.cpp]
|
|
|
|
[kitchen_sink_snippet_1]
|
|
|
|
the various algebraic operations between scalars, units, and quantities give
|
|
|
|
[kitchen_sink_output_1]
|
|
|
|
Scalar/unit operations :
|
|
|
|
[kitchen_sink_output_2]
|
|
|
|
Unit/unit operations and integral/rational powers of units :
|
|
|
|
[kitchen_sink_output_3]
|
|
|
|
Scalar/quantity operations :
|
|
|
|
[kitchen_sink_output_4]
|
|
|
|
Unit/quantity operations :
|
|
|
|
[kitchen_sink_output_5]
|
|
|
|
Quantity/quantity operations and integral/rational powers of quantities :
|
|
|
|
[kitchen_sink_output_6]
|
|
|
|
Logical comparison operators are also defined between quantities :
|
|
|
|
[kitchen_sink_snippet_2]
|
|
|
|
giving
|
|
|
|
[kitchen_sink_output_7]
|
|
|
|
Implicit conversion is allowed between dimensionless quantities and their corresponding value types :
|
|
|
|
[kitchen_sink_snippet_3]
|
|
|
|
A generic function for computing mechanical work can be defined that takes force and distance arguments
|
|
in an arbitrary unit system and returns energy in the same system:
|
|
|
|
[kitchen_sink_function_snippet_3]
|
|
|
|
[kitchen_sink_snippet_4]
|
|
|
|
which functions as expected for SI quantities :
|
|
|
|
[kitchen_sink_output_9]
|
|
|
|
The ideal gas law can also be implemented in SI units :
|
|
|
|
[kitchen_sink_function_snippet_4]
|
|
|
|
[kitchen_sink_snippet_5]
|
|
|
|
with the resulting output :
|
|
|
|
[kitchen_sink_output_10]
|
|
|
|
Trigonometric and inverse trigonometric functions can be implemented for any unit system
|
|
that provides an angular base dimension. For radians, these functions are found in
|
|
[headerref boost/units/cmath.hpp] These behave as one expects, with trigonometric functions
|
|
taking an angular quantity and returning a dimensionless quantity, while the inverse trigonometric functions
|
|
take a dimensionless quantity and return an angular quantity :
|
|
|
|
Defining a few angular quantities,
|
|
|
|
[kitchen_sink_snippet_6]
|
|
|
|
yields
|
|
|
|
[kitchen_sink_output_11]
|
|
|
|
Dealing with complex quantities is trivial. Here is the calculation of complex impedance :
|
|
|
|
[kitchen_sink_snippet_7]
|
|
|
|
giving
|
|
|
|
[kitchen_sink_output_12]
|
|
|
|
[section:UDT_Quantities User-defined value types]
|
|
|
|
User-defined value types that support the appropriate arithmetic operations are automatically supported
|
|
as quantity value types. The operators that are supported by default for quantity value types are unary plus, unary minus,
|
|
addition, subtraction, multiplication, division, equal-to, not-equal-to, less-than, less-or-equal-to,
|
|
greater-than, and greater-or-equal-to. Support for rational powers and roots can be added by overloading
|
|
the [___power_typeof_helper] and [___root_typeof_helper] classes. Here we implement a user-defined `measurement`
|
|
class that models a numerical measurement with an associated measurement error and the appropriate algebra and
|
|
demonstrates its use as a quantity value type; the full code is found in [@../../libs/units/example/measurement.hpp measurement.hpp].
|
|
|
|
Then, defining some `measurement` [___quantity] variables
|
|
|
|
[kitchen_sink_snippet_8]
|
|
|
|
gives
|
|
|
|
[kitchen_sink_output_13]
|
|
|
|
If we implement the overloaded helper classes for rational powers and roots
|
|
then we can also compute rational powers of measurement quantities :
|
|
|
|
[kitchen_sink_output_14]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:ConversionExample Conversion Example]
|
|
|
|
([@../../libs/units/example/conversion.cpp conversion.cpp])
|
|
|
|
This example demonstrates the various allowed conversions between SI and CGS units. Defining some
|
|
quantities
|
|
|
|
[import ../example/conversion.cpp]
|
|
|
|
[conversion_snippet_1]
|
|
|
|
illustrates implicit conversion of quantities of different value types where implicit conversion
|
|
of the value types themselves is allowed. N.B. The conversion from double to int is treated
|
|
as an explicit conversion because there is no way to emulate the exact behavior of the built-in
|
|
conversion. Explicit constructors allow conversions for two cases:
|
|
|
|
* explicit casting of a [___quantity] to a different `value_type` :
|
|
|
|
[conversion_snippet_3]
|
|
|
|
* and explicit casting of a [___quantity] to a different unit :
|
|
|
|
[conversion_snippet_4]
|
|
|
|
giving the following output :
|
|
|
|
[conversion_output_1]
|
|
|
|
A few more explicit unit system conversions :
|
|
|
|
[conversion_snippet_5]
|
|
|
|
which produces the following output:
|
|
|
|
[conversion_output_2]
|
|
|
|
[endsect]
|
|
|
|
[section:UDTExample User Defined Types]
|
|
|
|
([@../../libs/units/example/quaternion.cpp quaternion.cpp])
|
|
|
|
This example demonstrates the use of `boost::math::quaternion` as a value type for [___quantity] and the converse.
|
|
For the first case, we first define specializations of [___power_typeof_helper] and [___root_typeof_helper] for
|
|
powers and roots, respectively:
|
|
|
|
[import ../example/quaternion.cpp]
|
|
|
|
[quaternion_class_snippet_1a]
|
|
|
|
[quaternion_class_snippet_1b]
|
|
|
|
We can now declare a [___quantity] of a `quaternion` :
|
|
|
|
[quaternion_snippet_1]
|
|
|
|
so that all operations that are defined in the `quaternion` class behave correctly. If rational
|
|
powers were defined for this class, it would be possible to compute rational powers and roots with
|
|
no additional changes.
|
|
|
|
[quaternion_output_1]
|
|
|
|
Now, if for some reason we preferred the [___quantity] to be the value type of the `quaternion` class we would have :
|
|
|
|
[quaternion_snippet_2]
|
|
|
|
Here, the unary plus and minus and addition and subtraction operators function correctly. Unfortunately,
|
|
the multiplication and division operations fail because `quaternion` implements them in terms of the `*=` and
|
|
`/=` operators, respectively, which are incapable of representing the heterogeneous unit algebra needed for
|
|
quantities (an identical problem
|
|
occurs with `std::complex<T>`, for the same reason). In order to compute rational powers and roots, we need to
|
|
specialize [___power_typeof_helper] and [___root_typeof_helper] as follows:
|
|
|
|
[quaternion_class_snippet_2a]
|
|
|
|
[quaternion_class_snippet_2b]
|
|
|
|
giving:
|
|
|
|
[quaternion_output_2]
|
|
|
|
[endsect]
|
|
|
|
[section:ComplexExample Complex Example]
|
|
|
|
([@../../libs/units/example/complex.cpp complex.cpp])
|
|
|
|
This example demonstrates how to implement a replacement `complex` class that functions correctly both as a
|
|
quantity value type and as a quantity container class, including heterogeneous multiplication and division
|
|
operations and rational powers and roots. Naturally, heterogeneous operations are only supported on
|
|
compilers that implement `typeof`. The primary differences are that binary operations are not implemented
|
|
using the `op=` operators and use the utility classes [___add_typeof_helper], [___subtract_typeof_helper],
|
|
[___multiply_typeof_helper], and [___divide_typeof_helper]. In addition, [___power_typeof_helper] and
|
|
[___root_typeof_helper] are defined for both cases :
|
|
|
|
[import ../example/complex.cpp]
|
|
|
|
[complex_class_snippet_1]
|
|
|
|
With this replacement `complex` class, we can declare a complex variable :
|
|
|
|
[complex_snippet_1]
|
|
|
|
to get the correct behavior for all cases supported by [___quantity] with a `complex` value type :
|
|
|
|
[complex_output_1]
|
|
|
|
and, similarly, `complex` with a [___quantity] value type
|
|
|
|
[complex_snippet_2]
|
|
|
|
gives
|
|
|
|
[complex_output_2]
|
|
|
|
[endsect]
|
|
|
|
[section:PerformanceExample Performance Example]
|
|
|
|
([@../../libs/units/example/performance.cpp performance.cpp])
|
|
|
|
This example provides an ad hoc performance test to verify that zero runtime overhead
|
|
is incurred when using [___quantity] in place of `double`. Note that performance
|
|
optimization and testing is not trivial, so some care must be taken in profiling. It
|
|
is also critical to have a compiler capable of optimizing the many template instantiations
|
|
and inline calls effectively to achieve maximal performance. Zero overhead for this test
|
|
has been verified using gcc 4.0.1, and icc 9.0, 10.0, and 10.1 on Mac OS 10.4 and 10.5, and
|
|
using msvc 8.0 on Windows XP.
|
|
|
|
[endsect]
|
|
|
|
[section:RadarBeamHeightExample Radar Beam Height]
|
|
|
|
([@../../libs/units/example/radar_beam_height.cpp radar_beam_height.cpp])
|
|
|
|
[import ../example/radar_beam_height.cpp]
|
|
|
|
This example demonstrates the implementation of two non-SI units of length, the
|
|
nautical mile :
|
|
|
|
[radar_beam_height_class_snippet_1]
|
|
|
|
and the imperial foot :
|
|
|
|
[radar_beam_height_class_snippet_2]
|
|
|
|
These units include conversions between themselves and the meter. Three functions
|
|
for computing radar beam height from radar range and the local earth radius are
|
|
defined. The first takes arguments in one system and returns a value in the same
|
|
system :
|
|
|
|
[radar_beam_height_function_snippet_1]
|
|
|
|
The second is similar, but is templated on return type, so that the arguments are
|
|
converted to the return unit system internally :
|
|
|
|
[radar_beam_height_function_snippet_2]
|
|
|
|
Finally, the third function is an empirical approximation that is only valid for
|
|
radar ranges specified in nautical miles, returning beam height in feet. This
|
|
function uses the heterogeneous unit of nautical miles per square root of feet to
|
|
ensure dimensional correctness :
|
|
|
|
[radar_beam_height_function_snippet_3]
|
|
|
|
With these, we can compute radar beam height in various unit systems :
|
|
|
|
[radar_beam_height_snippet_1]
|
|
|
|
giving
|
|
|
|
[radar_beam_height_output]
|
|
|
|
[endsect]
|
|
|
|
[section:HeterogeneousUnitExample Heterogeneous Unit Example]
|
|
|
|
([@../../libs/units/example/heterogeneous_unit.cpp heterogeneous_unit.cpp])
|
|
|
|
[import ../example/heterogeneous_unit.cpp]
|
|
|
|
Mixed units and mixed unit conversions.
|
|
|
|
This code:
|
|
|
|
[heterogeneous_unit_snippet_1]
|
|
|
|
gives
|
|
|
|
[heterogeneous_unit_output_1]
|
|
|
|
Arbitrary conversions also work:
|
|
|
|
[heterogeneous_unit_snippet_2]
|
|
|
|
yielding
|
|
|
|
[heterogeneous_unit_output_2]
|
|
|
|
[endsect]
|
|
|
|
[section:AbsoluteRelativeTemperatureExample Absolute and Relative Temperature Example]
|
|
|
|
([@../../libs/units/example/temperature.cpp temperature.cpp])
|
|
|
|
[import ../example/temperature.cpp]
|
|
|
|
This example demonstrates using of absolute temperatures and relative temperature differences in Fahrenheit
|
|
and converting between these and the Kelvin temperature scale. This issue touches on some surprisingly deep mathematical
|
|
concepts (see [@http://en.wikipedia.org/wiki/Affine_space Wikipedia] for a basic review), but for our purposes here, we
|
|
will simply observe that it is important to be able to differentiate between an absolute temperature measurement and a
|
|
measurement of temperature difference. This is accomplished by using the [___absolute] wrapper class.
|
|
|
|
First we define a system using the predefined fahrenheit base unit:
|
|
|
|
[temperature_snippet_1]
|
|
|
|
Now we can create some quantities:
|
|
|
|
[temperature_snippet_3]
|
|
|
|
Note the use of [___absolute] to wrap a unit. The resulting output is:
|
|
|
|
[temperature_output_1]
|
|
|
|
[endsect]
|
|
|
|
[section:RuntimeConversionFactorExample Runtime Conversion Factor Example]
|
|
|
|
([@../../libs/units/example/runtime_conversion_factor.cpp runtime_conversion_factor.cpp])
|
|
|
|
[import ../example/runtime_conversion_factor.cpp]
|
|
|
|
The Boost.Units library does not require that the conversion factors be compile time constants,
|
|
as is demonstrated in this example:
|
|
|
|
[runtime_conversion_factor_snippet_1]
|
|
|
|
[endsect]
|
|
|
|
[section:UnitsWithNonbaseDimensions Units with Non-base Dimensions]
|
|
|
|
([@../../libs/units/example/non_base_dimension.cpp non_base_dimension.cpp])
|
|
|
|
[import ../example/non_base_dimension.cpp]
|
|
|
|
It is also possible to define base units that have derived rather than base dimensions:
|
|
|
|
[non_base_dimension_snippet_1]
|
|
|
|
[endsect]
|
|
|
|
[section:OutputForCompositeUnits Output for Composite Units]
|
|
|
|
([@../../libs/units/example/composite_output.cpp composite_output.cpp])
|
|
|
|
[import ../example/composite_output.cpp]
|
|
|
|
If a unit has a special name and/or symbol, the free functions `name_string` and
|
|
`symbol_string` can be overloaded directly.
|
|
|
|
[composite_output_snippet_1]
|
|
|
|
In this case, any unit that reduces
|
|
to the overloaded unit will be output with the replacement symbol.
|
|
|
|
Special names and symbols for the SI and CGS unit systems are found in
|
|
[headerref boost/units/systems/si/io.hpp] and [headerref boost/units/systems/cgs/io.hpp],
|
|
respectively. If these headers are not included, the output will simply follow
|
|
default rules using the appropriate fundamental dimensions.
|
|
Note that neither of these functions is defined for quantities
|
|
because doing so would require making assumptions on how the corresponding value
|
|
type should be formatted.
|
|
|
|
Three `ostream` formatters, `symbol_format`, `name_format`, and `typename_format`
|
|
are provided for convenience. These select the textual representation of units
|
|
provided by `symbol_string` or `name_string` in the first two cases, while the
|
|
latter returns a demangled typename for debugging purposes. Formatting of scaled
|
|
unit is also done correctly.
|
|
|
|
[endsect]
|
|
|
|
[section:autoscale 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 [@http://en.wikipedia.org/wiki/Engineering_notation 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.
|
|
|
|
[import ../example/autoprefixes.cpp]
|
|
|
|
[autoprefixes_snippet_1]
|
|
|
|
(The complete set of [@http://physics.nist.gov/cuu/Units/prefixes.html 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 [@http://en.wikipedia.org/wiki/Binary_prefixes 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 [@http://physics.nist.gov/cuu/Units/binary.html 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).
|
|
|
|
[autoprefixes_snippet_2]
|
|
|
|
But note that scalar dimensionless values, like int, float and double,
|
|
are *not* prefixed automatically by the engineering_prefix or binary_prefix iostream manipulators.
|
|
|
|
[autoprefixes_snippet_3]
|
|
|
|
You can output the name or symbol of a unit (rather than the most common quantity of a unit).
|
|
|
|
[autoprefixes_snippet_4]
|
|
|
|
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:
|
|
|
|
[autoprefixes_snippet_5]
|
|
|
|
And you can get the format flags for diagnosing problems.
|
|
|
|
[autoprefixes_snippet_6]
|
|
|
|
[endsect] [/section:autoscale Automatically Scaled Units]
|
|
|
|
[section:ConversionFactor Conversion Factor]
|
|
|
|
This code demonstrates the use of the `conversion_factor` free function to determine
|
|
the scale factor between two units.
|
|
|
|
([@../../libs/units/example/conversion_factor.cpp conversion_factor.cpp])
|
|
|
|
[import ../example/conversion_factor.cpp]
|
|
|
|
[conversion_factor_snippet_1]
|
|
|
|
Produces
|
|
|
|
[conversion_factor_output]
|
|
|
|
[endsect]
|
|
|
|
[section:RuntimeUnits Runtime Units]
|
|
|
|
([@../../libs/units/example/runtime_unit.cpp runtime_unit.cpp])
|
|
|
|
[import ../example/runtime_unit.cpp]
|
|
|
|
This example shows how to implement an interface that
|
|
allow different units at runtime while still maintaining
|
|
type safety for internal calculations.
|
|
|
|
[runtime_unit_snippet_1]
|
|
|
|
[endsect]
|
|
|
|
[section:lambda Interoperability with Boost.Lambda]
|
|
|
|
([@../../libs/units/example/lambda.cpp lambda.cpp])
|
|
|
|
[import ../example/lambda.cpp]
|
|
|
|
The header [headerref boost/units/lambda.hpp] provides overloads
|
|
and specializations needed to make Boost.Units usable with the
|
|
Boost.Lambda library.
|
|
|
|
[lambda_snippet_1]
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:Utilities Utilities]
|
|
|
|
Relatively complete SI and CGS unit systems are provided in [headerref boost/units/systems/si.hpp] and
|
|
[headerref boost/units/systems/cgs.hpp], respectively.
|
|
|
|
[section:Metaprogramming_Classes Metaprogramming Classes]
|
|
|
|
template<long N> struct ordinal<N>;
|
|
|
|
template<typename T,typename V> struct get_tag< dim<T,V> >;
|
|
template<typename T,typename V> struct get_value< dim<T,V> >;
|
|
template<class S,class DT> struct get_system_tag_of_dim<S,DT>;
|
|
template<typename Seq> struct make_dimension_list<Seq>;
|
|
template<class DT> struct fundamental_dimension<DT>;
|
|
template<class DT1,int E1,...> struct composite_dimension<DT1,E1,...>;
|
|
|
|
template<class Dim,class System> struct get_dimension< unit<Dim,System> >;
|
|
template<class Unit,class Y> struct get_dimension< quantity<Unit,Y> >;
|
|
template<class Dim,class System> struct get_system< unit<Dim,System> >;
|
|
template<class Unit,class Y> struct get_system quantity<Unit,Y> >;
|
|
|
|
struct dimensionless_type;
|
|
template<class System> struct dimensionless_unit<System>;
|
|
template<class System,class Y> struct dimensionless_quantity<System,Y>;
|
|
|
|
struct implicitly_convertible;
|
|
struct trivial_conversion;
|
|
template<class T,class S1,class S2> struct base_unit_converter<T,S1,S2>;
|
|
|
|
template<class Q1,class Q2> class conversion_helper<Q1,Q2>;
|
|
|
|
[endsect]
|
|
|
|
[section:Metaprogramming_Predicates Metaprogramming Predicates]
|
|
|
|
template<typename T,typename V> struct is_dim< dim<T,V> >;
|
|
template<typename T,typename V> struct is_empty_dim< dim<T,V> >;
|
|
|
|
template<typename Seq> struct is_dimension_list<Seq>;
|
|
|
|
template<class S> struct is_system< homogeneous_system<S> >;
|
|
template<class S> struct is_system< heterogeneous_system<S> >;
|
|
template<class S> struct is_homogeneous_system< homogeneous_system<S> >;
|
|
template<class S> struct is_heterogeneous_system< heterogeneous_system<S> >;
|
|
|
|
template<class Dim,class System> struct is_unit< unit<Dim,System> >;
|
|
template<class Dim,class System> struct is_unit_of_system< unit<Dim,System>,System >;
|
|
template<class Dim,class System> struct is_unit_of_dimension< unit<Dim,System>,Dim >;
|
|
|
|
template<class Unit,class Y> struct is_quantity< quantity<Unit,Y> >;
|
|
template<class Dim,class System,class Y> struct is_quantity_of_system< quantity<unit<Dim,System>,Y>,System >;
|
|
template<class Dim,class System,class Y> struct is_quantity_of_dimension< quantity<unit<Dim,System>,Y>,Dim >;
|
|
|
|
template<class System> struct is_dimensionless< unit<dimensionless_type,System> >;
|
|
template<class System> struct is_dimensionless_unit< unit<dimensionless_type,System> >;
|
|
template<class System,class Y> struct is_dimensionless< quantity<unit<dimensionless_type,System>,Y> >;
|
|
template<class System,class Y> struct is_dimensionless_quantity< quantity<unit<dimensionless_type,System>,Y> >;
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:Reference Reference]
|
|
|
|
[xinclude units_reference.xml]
|
|
|
|
[xinclude dimensions_reference.xml]
|
|
[xinclude si_reference.xml]
|
|
[xinclude cgs_reference.xml]
|
|
[xinclude trig_reference.xml]
|
|
[xinclude temperature_reference.xml]
|
|
[xinclude information_reference.xml]
|
|
[xinclude abstract_reference.xml]
|
|
|
|
[section Base Units by Category]
|
|
|
|
[xinclude angle_base_units_reference.xml]
|
|
[xinclude astronomical_base_units_reference.xml]
|
|
[xinclude cgs_base_units_reference.xml]
|
|
[xinclude imperial_base_units_reference.xml]
|
|
[xinclude metric_base_units_reference.xml]
|
|
[xinclude si_base_units_reference.xml]
|
|
[xinclude temperature_base_units_reference.xml]
|
|
[xinclude us_base_units_reference.xml]
|
|
|
|
[endsect]
|
|
|
|
[section Alphabetical Listing of Base Units]
|
|
[include base_units.qbk]
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:Installation Installation]
|
|
|
|
The core header files are located in `boost/units`. Unit system headers are
|
|
located in `<boost/units/systems>`. There are no source files for the library
|
|
itself - the library is header-only. Example programs demonstrating various aspects of the library can be found in
|
|
`boost/libs/units/example`. Programs for unit testing are provided in `boost/libs/units/test`.
|
|
|
|
[endsect]
|
|
|
|
[section:FAQ FAQ]
|
|
|
|
[section:Distinguishing_Quantities_With_Same_Units
|
|
How does one distinguish between quantities that are physically different but have the same units (such as
|
|
energy and torque)?]
|
|
|
|
Because Boost.Units includes plane and solid angle units in the SI system, torque and energy
|
|
are, in fact, distinguishable (see [@http://en.wikipedia.org/wiki/SI_units torque]).
|
|
In addition, energy is a true
|
|
[@http://mathworld.wolfram.com/Scalar.html scalar] quantity, while torque, despite
|
|
having the same units as energy if plane angle is not included, is in fact a
|
|
[@http://mathworld.wolfram.com/Pseudovector.html pseudovector]. Thus, a value type representing pseudovectors
|
|
and encapsulating their algebra could also be implemented.
|
|
|
|
There are,
|
|
however, a few SI units that are dimensionally indistinguishable within the SI system. These
|
|
include the [@http://en.wikipedia.org/wiki/Becquerel becquerel], which has units identical to
|
|
frequency (Hz), and the [@http://en.wikipedia.org/wiki/Sievert sievert], which is degenerate
|
|
with the [@http://en.wikipedia.org/wiki/Gray_%28unit%29 gray]. In cases such as this,
|
|
the proper way to treat this difference is to recognize that expanding the set of base dimensions
|
|
can provide disambiguation. For example, adding a base dimension for radioactive decays would
|
|
allow the becquerel to be written as decays/second, differentiating it from the signature of hertz,
|
|
which is simply 1/second.
|
|
|
|
[endsect]
|
|
|
|
[section:Angle_Are_Units Angles are treated as units]
|
|
|
|
If you don't like this, you can just ignore the angle units and
|
|
go on your merry way (periodically screwing up when a routine wants degrees and you give it
|
|
radians instead...)
|
|
|
|
[endsect]
|
|
|
|
[section:Why_Homogeneous_Systems Why are there homogeneous systems? Aren't heterogeneous systems sufficient?]
|
|
|
|
Consider the following code:
|
|
|
|
cout << asin(sin(90.0 * degrees));
|
|
|
|
What should this print? If only heterogeneous
|
|
systems are available it would print 1.5708 rad
|
|
Why? Well, `sin` would return a `quantity<dimensionless>`
|
|
effectively losing the information that degrees
|
|
are being used. In order to propogate this extra information
|
|
we need homogeneous systems.
|
|
|
|
[endsect]
|
|
|
|
[section:NoConstructorFromValueType Why can't I construct a quantity directly from the value type?]
|
|
|
|
This only breaks generic code--which ought to break anyway. The only
|
|
literal value that ought to be converted to a quantity by generic code
|
|
is zero, which should be handled by the default constructor. In addition,
|
|
consider the search and replace problem allowing this poses:
|
|
|
|
quantity<si::length> q(1.0);
|
|
|
|
Here, the intent is clear - we want a length of one in the SI system, which is one meter. However,
|
|
imagine some well-intentioned coder attempting to reuse this code, but to have it perform the
|
|
calculations in the CGS unit system instead. After searching for `si::` and replacing it with `cgs::` ,
|
|
we have:
|
|
|
|
quantity<cgs::length> q(1.0);
|
|
|
|
Unfortunately, the meaning of this statement has suddenly changed from one meter to one centimeter. In
|
|
contrast, as implemented, we begin with:
|
|
|
|
quantity<si::length> q(1.0*si::meter);
|
|
|
|
and, after search and replace:
|
|
|
|
quantity<cgs::length> q(1.0*cgs::meter);
|
|
|
|
which gives us an error. Even if the code has a @using namespace boost::units::si; declaration, the latter
|
|
is still safe, with:
|
|
|
|
using namespace boost::units::si;
|
|
quantity<length> q(1.0*meter);
|
|
|
|
going to
|
|
|
|
using namespace boost::units::cgs;
|
|
quantity<length> q(1.0*meter);
|
|
|
|
The latter will involve an explicit conversion from meters to centimeters, but the value remains correct.
|
|
|
|
[endsect]
|
|
|
|
[section:ExplicitConversions Why are conversions explicit by default?]
|
|
|
|
Safety and the potential for unintended conversions leading to precision loss and hidden performance costs.
|
|
Options are provided for forcing implicit conversions between specific units to be allowed.
|
|
|
|
[endsect]
|
|
|
|
[endsect]
|
|
|
|
[section:Acknowledgements Acknowledgements]
|
|
|
|
Matthias C. Schabel would like to acknowledge the Department of Defense for its support of this work under
|
|
the Prostate Cancer Research Program New Investigator Award W81XWH-04-1-0042 and the National Institutes of Health for their
|
|
support of this work under the NIBIB Mentored Quantitative Research Development Award K25EB005077.
|
|
|
|
Thanks to David Walthall for his assistance in debugging and testing on a variety of platforms and Torsten Maehne for
|
|
his work on interfacing the Boost Units and Boost Lambda libraries.
|
|
|
|
Thanks to:
|
|
|
|
* Paul Bristow,
|
|
* Michael Fawcett,
|
|
* Ben FrantzDale,
|
|
* Ron Garcia,
|
|
* David Greene,
|
|
* Peder Holt,
|
|
* Janek Kozicki,
|
|
* Andy Little,
|
|
* Kevin Lynch,
|
|
* Torsten Maehne
|
|
* Noah Roberts,
|
|
* Andrey Semashev,
|
|
* David Walthall,
|
|
* Deane Yang,
|
|
|
|
and all the members of the Boost mailing list who provided their input into
|
|
the design and implementation of this library.
|
|
|
|
[endsect] [/section:Acknowledgements Acknowledgements]
|
|
|
|
[section:HelpWanted Help Wanted]
|
|
|
|
Any help in the following areas would be much appreciated:
|
|
|
|
* testing on other compilers and operating systems
|
|
* performance testing on various architectures
|
|
* tutorials
|
|
|
|
[endsect]
|
|
|
|
[section:version_id Version Info]
|
|
|
|
__boostroot
|
|
|
|
Last edit to Quickbook file __FILENAME__ was at __TIME__ on __DATE__.
|
|
|
|
[tip This should appear on the pdf version (but may be redundant on html).]
|
|
[/ Useful on pdf version. See also Last revised timestamp on first page of html version.]
|
|
[/See also Adobe Reader pdf File Properties for creation date, and PDF producer, version and page count.]
|
|
|
|
[endsect] [/section:version_id Version Info]
|
|
|
|
[section:ReleaseNotes Release Notes]
|
|
|
|
1.2 (March 2010)
|
|
|
|
* Added autoprefix ready for Boost 1.43
|
|
|
|
1.0.0 (August 1, 2008) :
|
|
|
|
* Initial release with Boost 1.36
|
|
|
|
0.7.1 (March 14, 2007) :
|
|
|
|
* Boost.Typeof emulation support.
|
|
* attempting to rebind a heterogeneous_system to a different set of dimensions now fails.
|
|
* cmath.hpp now works with como-win32.
|
|
* minor changes to the tests and examples to make msvc 7.1 happy.
|
|
|
|
0.7.0 (March 13, 2007) :
|
|
|
|
* heterogeneous and mixed system functionality added.
|
|
* added fine-grained implicit unit conversion on a per fundamental dimension basis.
|
|
* added a number of utility metafunction classes and predicates.
|
|
* [headerref boost/units/operators.hpp] now uses `BOOST_TYPEOF` when possible.
|
|
* angular units added in [headerref boost/units/systems/angle/gradians.hpp]
|
|
and [headerref boost/units/systems/angle/gradians.hpp].
|
|
Implicit conversion of radians between trigonometric, SI, and CGS systems is allowed.
|
|
* a variety of [___unit] and [___quantity] tests added.
|
|
* examples now provide self-tests.
|
|
|
|
0.6.2 (February 22, 2007) :
|
|
|
|
* changed template order in `unit` so dimension precedes unit system
|
|
* added `homogeneous_system<S>` for unit systems
|
|
* incorporated changes to [headerref boost/units/dimension.hpp] (compile-time sorting by predicate),
|
|
[headerref boost/units/conversion.hpp] (thread-safe implementation of quantity conversions),
|
|
and [headerref boost/units/io.hpp] (now works with any `std::basic_ostream`) by SW
|
|
* added abstract units in [headerref boost/units/systems/abstract.hpp] to allow abstract dimensional
|
|
analysis
|
|
* new example demonstrating implementation of code based on requirements from
|
|
Michael Fawcett ([@../../libs/units/example/radar_beam_height.cpp radar_beam_height.cpp])
|
|
|
|
0.6.1 (February 13, 2007) :
|
|
|
|
* added metafunctions to test if a type is
|
|
* a valid dimension list (`is_dimension_list<D>`)
|
|
* a unit (`is_unit<T>` and `is_unit_of_system<U,System>`)
|
|
* a quantity (`is_quantity<T>` and `is_quantity_of_system<Q,System>`)
|
|
* quantity conversion factor is now computed at compile time
|
|
* static constants now avoid ODR problems
|
|
* unit_example_14.cpp now uses Boost.Timer
|
|
* numerous minor fixes suggested by SW
|
|
|
|
0.6.0 (February 8, 2007) :
|
|
|
|
* incorporated Steven Watanabe's optimized code for dimension.hpp, leading to *dramatic*
|
|
decreases in compilation time (nearly a factor of 10 for unit_example_4.cpp in my tests).
|
|
|
|
0.5.8 (February 7, 2007) :
|
|
|
|
* fixed `#include` in [headerref boost/units/systems/si/base.hpp] (thanks to Michael Fawcett and
|
|
Steven Watanabe)
|
|
* removed references to obsolete `base_type` in [___unit_info] (thanks to Michael Fawcett)
|
|
* moved functions in [headerref boost/units/cmath.hpp] into `boost::units` namespace
|
|
(thanks to Steven Watanabe)
|
|
* fixed `#include` guards to be consistently named `BOOST_UNITS_XXX` (thanks to Steven
|
|
Watanabe)
|
|
|
|
0.5.7 (February 5, 2007) :
|
|
|
|
* changed quantity conversion helper to increase flexibility
|
|
* minor documentation changes
|
|
* submitted for formal review as a Boost library
|
|
|
|
0.5.6 (January 22, 2007) :
|
|
|
|
* added IEEE 1541 standard binary prefixes along with SI prefixes to and extended algebra of
|
|
`scale` and `scaled_value` classes (thanks to Kevin Lynch)
|
|
* split SI units into separate header files to minimize the "kitchen sink" include problem
|
|
(thanks to Janek Kozicki)
|
|
* added convenience classes for declaring fundamental dimensions and composite dimensions
|
|
with integral powers (`fundamental_dimension` and `composite_dimension` respectively)
|
|
|
|
0.5.5 (January 18, 2007) :
|
|
|
|
* template parameter order in `quantity` switched and default `value_type` of `double` added
|
|
(thanks to Andrey Semashev and Paul Bristow)
|
|
* added implicit `value_type` conversion where allowed (thanks to Andrey Semashev)
|
|
* added `quantity_cast` for three cases (thanks to Andrey Semashev):
|
|
* constructing `quantity` from raw `value_type`
|
|
* casting from one `value_type` to another
|
|
* casting from one `unit` to another (where conversion is allowed)
|
|
* added` metre` and `metres` and related constants to the SI system for the convenience of
|
|
our Commonwealth friends...
|
|
|
|
0.5.4 (January 12, 2007) :
|
|
|
|
* completely reimplemented unit conversion to allow for arbitrary unit conversions
|
|
between systems
|
|
* strict quantity construction is default; quantities can be constructed from bare values
|
|
by using static member `from_value`
|
|
|
|
0.5.3 (December 12, 2006) :
|
|
|
|
* added Boost.Serialization support to `unit` and `quantity` classes
|
|
* added option to enforce strict construction of quantities (only constructible
|
|
by multiplication of scalar by unit or quantity by unit) by preprocessor
|
|
`MCS_STRICT_QUANTITY_CONSTRUCTION` switch
|
|
|
|
0.5.2 (December 4, 2006) :
|
|
|
|
* added `<cmath>` wrappers in the `std` namespace for functions that can support quantities
|
|
|
|
0.5.1 (November 3, 2006) :
|
|
|
|
* converted to Boost Software License
|
|
* boostified directory structure and file paths
|
|
|
|
0.5 (November 2, 2006) :
|
|
|
|
* completely reimplemented SI and CGS unit systems and changed syntax for quantities
|
|
* significantly streamlined `pow` and `root` so for most applications it is only
|
|
necessary to define `power_typeof_helper` and `root_typeof_helper` to gain this
|
|
functionality
|
|
* added a selection of physical constants from the CODATA tables
|
|
* added a skeleton `complex` class that correctly supports both `complex<quantity<Y,Unit> >`
|
|
and `quantity<complex<Y>,Unit>` as an example
|
|
* investigate using Boost.Typeof for compilers that do not support `typeof`
|
|
|
|
0.4 (October 13, 2006) :
|
|
|
|
* `pow<R>` and `root<R>` improved for user-defined types
|
|
* added unary + and unary - operators
|
|
* added new example of interfacing with `boost::math::quaternion`
|
|
* added optional preprocessor switch to enable implicit unit conversions
|
|
(`BOOST_UNITS_ENABLE_IMPLICIT_UNIT_CONVERSIONS`)
|
|
|
|
0.3 (September 6, 2006) :
|
|
|
|
* Support for `op(X x,Y y)` for g++ added. This is automatically
|
|
active when compiling with gcc and can be optionally enabled by defining the preprocessor
|
|
constant `BOOST_UNITS_HAS_TYPEOF`
|
|
|
|
0.2 (September 4, 2006) : Second alpha release based on slightly modified code from 0.1 release
|
|
|
|
0.1 (December 13, 2003) : written as a Boost demonstration of MPL-based dimensional analysis
|
|
in 2003.
|
|
|
|
[endsect]
|
|
|
|
[section:TODO TODO]
|
|
|
|
* Document concepts
|
|
* Implementation of I/O is rudimentary; consider methods of i18n using facets
|
|
* Consider runtime variant, perhaps using overload like `quantity<runtime,Y>`
|
|
|
|
[endsect] [/section:TODO TODO]
|