Spis treści

Biblioteka boost - boost::units

Wprowadzenie

Biblioteka ta pozwala definiować systemy jednostek, służących do obliczeń ilościowych. Umożliwia prowadzenie obliczeń w jednostkach z różnych systemów, pod warunkiem, że prawa konwersji jednostek zostały zdefiniowane.

Obliczenia mogą być prowadzone na wartościach reprezentowanych przez zmienne, bez zwracania uwagi na jednostki, ponieważ rachunek jednostkowy będzie przeprowadzony implicite.

Pomocne źródła

przykładowy kod źródłowy:

/**
 * Stanisław Nowak, I1ISI
 * 
 * Ponizszy kod daje przyklad zastosowania biblioteki boost::units
 * 
 * Biblioteka ta pozwala definiować systemy jednostek, umozliwiajac proste konwersje i 
 * kalkulacje na jednostkach. Mozna rowniez wykonywac obliczenia na jednostkach roznych
 * systemow (np. kalkulacje angazujace jednostki metr i stopa)
 * 
 * W pierwszej czesci kodu definiowany jest system jednostek. Tworzone sa 3 podstawowe
 * wymiary jednostek:
 *   - length_dimension - dla jednostek dlugosci
 *   - mass_dimension   - dla jednostek masy
 *   - time_dimension   - dla jesnostek czasu
 *   
 * Nastepnie tworzone sa wymiary pochodne od podstawowych, jako ich kombinacje liniowe.
 * Tworzone sa jednostki odpowiadajace zdefiniowanym wymiarom. Na ich podstawie powstaje
 * system jednostek, w ktorych prowadzone beda obliczenia.
 * 
 * W dalszej czesci tworzone sa struktury wspomagajace deklarowanie, uzywanie i wypisywanie
 * zmiennych reprezentujacych wartosci poszczegolnych typow.
 * 
 * Komentarze staralem sie umieszczac bezposrednio przed instrukcjami, do ktorego sie odnosza.
 * 
 * Przykład bazuje na prostym systemie jednostek zdefiniowanym i umieszczonym na stronie
 * http://www.boost.org/doc/libs/1_38_0/doc/html/boost_units/Examples.html. Ponizej znajduje
 * sie notka licencyjna.
 * 
 * Boost.Units - A C++ library for zero-overhead dimensional analysis and 
 * unit/quantity manipulation and conversion
 * 
 * Copyright (C) 2003-2008 Matthias Christian Schabel
 * Copyright (C) 2008 Steven Watanabe
 * 
 * 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)
 */
 
#include <iostream>
 
#include <boost/mpl/list.hpp>
#include <boost/mpl/vector.hpp>
 
#include <boost/units/pow.hpp>			//definiowanie jednostek skalowanych i potegowanie
#include <boost/units/quantity.hpp>		//uzywanie jednostek do obliczeń ilosciowych
#include <boost/units/io.hpp>			//obsluga base_unit_info
#include <boost/units/base_dimension.hpp>	//definiowanie wymiarow podstawowych jednostek
#include <boost/units/derived_dimension.hpp>	//tworzenie jednostek pochodnych od podstawowych
#include <boost/units/static_constant.hpp>	//definiowanie stalych do deklaracji zmiennych
#include <boost/units/unit.hpp>			//podstawowy naglowek
#include <boost/units/base_unit.hpp>		//tworzenie podstawowych jednostek skojarzonych z odpowiednim wymiarem
#include <boost/units/make_system.hpp>		//tworzenie systemu jednostek
 
namespace boost {
namespace units {
 
/**
 * Podstawowe wymiary jednostek: dlugosc, masa, czas
 */
struct length_base_dimension : base_dimension<length_base_dimension,1> { };
struct mass_base_dimension   : base_dimension<mass_base_dimension,2> { };
struct time_base_dimension   : base_dimension<time_base_dimension,3> { };
 
typedef length_base_dimension::dimension_type    length_dimension;
typedef   mass_base_dimension::dimension_type    mass_dimension;
typedef   time_base_dimension::dimension_type    time_dimension;
 
/**
 * Wymiary pochodne: zdefiniowane na podstawie podstawowych wymiarow jednostek.
 * Prosze zwrocic uwage na definicje wymiaru energii. Podane zostaly wykladniki
 * wymiarow jednostek podstawowych skladajacych sie na dany wymiar pochodny.
 */
typedef derived_dimension<	length_base_dimension,2>::type	area_dimension;
typedef derived_dimension<	mass_base_dimension,1,		//kilogram..
                          	length_base_dimension,2,	//metr..
                          	time_base_dimension,-2>::type	energy_dimension;	//przez sekunde kwadrat
 
namespace test {
 
/**
 * Definicja jednostek podstawowych dla poszczegolnych wymiarow: metr, kilogram, sekunda.
 * Jednostki podstawowe posluza do stworzenia systemu jednostkowego na ich podstawie
 */
struct meter_base_unit :	base_unit<   meter_base_unit, length_dimension, 1> { };
struct kilogram_base_unit :	base_unit<kilogram_base_unit,   mass_dimension, 2> { };
struct second_base_unit :	base_unit<  second_base_unit,   time_dimension, 3> { };
 
/**
 * Definicja systemu jesnostek. Jako podstawowe definiujemy metr, kilogram, sekunda.
 */
typedef make_system<
    meter_base_unit,
    kilogram_base_unit,
    second_base_unit>::type mks_system;
 
/**
 * Tworzymy skrocone nazwy jednostek skojarzonych z odpowiednimi wymiarami.
 * Jednostki musza nalezec do uprzednio zdefiniowanego systemu jednoskowego
 */
typedef unit<dimensionless_type,mks_system>      dimensionless;
 
typedef unit<length_dimension,mks_system>        length;
typedef unit<  mass_dimension,mks_system>        mass;
typedef unit<  time_dimension,mks_system>        time;
 
typedef unit<  area_dimension,mks_system>        area;
typedef unit<energy_dimension,mks_system>        energy;
 
/**
 * Tworzenie stalych dla jednostek. Ponizsze makro jest dostarczone w naglowku
 * boost/units/static_constant.hpp. Dzieki temu stale te sa bezpieczne w uzyciu
 * z watkami. Pomagaja rowniez w pozniejszej deklaracji zmiennych.
 * Stalych tych mozna uzywac w kodzie programu w naturalny dla czlowieka sposob,
 * zaraz po wartosci np. "4*seconds".
 */
BOOST_UNITS_STATIC_CONSTANT(meter,length);
BOOST_UNITS_STATIC_CONSTANT(meters,length);
BOOST_UNITS_STATIC_CONSTANT(kilogram,mass);
BOOST_UNITS_STATIC_CONSTANT(kilograms,mass);
BOOST_UNITS_STATIC_CONSTANT(second,time);
BOOST_UNITS_STATIC_CONSTANT(seconds,time);
BOOST_UNITS_STATIC_CONSTANT(square_meter,area);
BOOST_UNITS_STATIC_CONSTANT(square_meters,area);
BOOST_UNITS_STATIC_CONSTANT(joule,energy);
BOOST_UNITS_STATIC_CONSTANT(joules,energy);
} // namespace test
 
/**
 * Tworzymy obsluge napisowego opisu jednostek. Sluza one do wyprowadzania
 * wynikow obliczen na konsole lub innego strumienia. Mozna zdefiniowac pelna
 * nazwe jednostki i jej symbol. Funkcje te sa uzywane implicite przez operator
 * << dla strumieni.
 */
template<> struct base_unit_info<test::meter_base_unit>
{
    static std::string name()               { return "meter"; }
    static std::string symbol()             { return "m"; }
};
 
template<> struct base_unit_info<test::kilogram_base_unit>
{
    static std::string name()               { return "kilogram"; }
    static std::string symbol()             { return "kg"; }
};
 
template<> struct base_unit_info<test::second_base_unit>
{
    static std::string name()               { return "second"; }
    static std::string symbol()             { return "s"; }
};
 
} // namespace units
} // namespace boost
 
/**
 * Cialo programu testujacego
 */
int main(void)
{
    using namespace boost::units;
    using namespace boost::units::test;
 
    {
    /**
     * Deklaracja zmiennych skojarzonych z odpowiednia jednostka.
     */
    quantity<length> L = 2.0*meters;                     
    quantity<energy> E = kilograms*pow<2>(L/seconds);
 
    /**
     * Demonstracja obliczeń wykonywanych na jednostkach.
     * Prosze zwrocic uwage na zastosowanie stalych "kilograms", "seconds", itp.
     */
    std::cout << "L                                 = " << L		<< std::endl
              << "L+L                               = " << L+L		<< std::endl
              << "L-L                               = " << L-L		<< std::endl
              << "L*L                               = " << L*L		<< std::endl
              << "L/L                               = " << L/L		<< std::endl
              << "L*meter                           = " << L*meter	<< std::endl
              << "kilograms*(L/seconds)*(L/seconds) = "
              << kilograms*(L/seconds)*(L/seconds)			<< std::endl
              << "kilograms*(L/seconds)^2           = "
              << kilograms*pow<2>(L/seconds)				<< std::endl
              << "L^3                               = "
              << pow<3>(L)						<< std::endl
              << "L^(3/2)                           = "
              << pow<static_rational<3,2> >(L)				<< std::endl
              << "2vL                               = "
              << root<2>(L)						<< std::endl
              << "(3/2)vL                           = "
              << root<static_rational<3,2> >(L)				<< std::endl
              << std::endl;
    }
    return 0;
}

Autor

Stanisław Nowak, I1ISI
snowak2@stud.elka.pw.edu.pl