![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
User's GuideBoost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 31. Boost.Ratio 2.1.0
|
![]() |
Note |
---|---|
Пожалуйста, сообщите нам, как это работает на других платформах/компиляторах. |
![]() |
Note |
---|---|
Пожалуйста, присылайте любые вопросы, комментарии и отчеты об ошибках, чтобы увеличить списки |
ratio
- это общая цель, вдохновленная Уолтером Брауном, позволяющая легко и безопасно вычислять рациональные ценности в компиляционное время. ratio
класс ловит все ошибки (такие как деление на ноль и перегрузка) во время компиляции. Он используется в продолжительности и time_point
классы для эффективного создания единиц времени. Он также может быть использован в других библиотеках «количество» или в любом месте есть рациональная константа, которая известна во время компиляции. Использование этой утилиты может значительно снизить шансы переполнения времени, потому что ratio
(и любые соотношения в результате ratio
арифметика) всегда сводятся к самым низким условиям.
ratio
является шаблоном, забирающим два intmax_ts
, со вторым по умолчанию до 1. В дополнение к копированию конструкторов и присвоению, он имеет только двух публичных членов, оба из которых являются статичными const intmax_t
. Один - числитель ratio
, а другой - знаменатель. ratio
всегда нормализуется таким образом, что он выражается в самых низких терминах, а знаменатель всегда положительный. Когда числитель 0, знаменатель всегда 1.
Пример:
typedefratio
<5, 3> five_thirds; // five_thirds::num == 5, five_thirds::den == 3 typedefratio
<25, 15> also_five_thirds; // also_five_thirds::num == 5, also_five_thirds::den == 3 typedef ratio_divide<five_thirds, also_five_thirds>::type one; // one::num == 1, one::den == 1
Этот объект также включает в себя удобные типы для префиксов SI atto
через exa
, соответствующие их международно признанным определениям (в терминах ratio<34>
). Это огромное синтаксическое удобство. Это предотвратит ошибки при указании констант, поскольку больше не нужно удваивать количество нолей при попытке написать миллионы или миллиарды.
Пример:
typedef ratio_multiply<ratio
<5>, giga>::type _5giga; // _5giga::num == 5000000000, _5giga::den == 1 typedef ratio_multiply<ratio
<5>, nano>::type _5nano; // _5nano::num == 1, _5nano::den == 200000000
Для каждого ratio<N, D>
существует ratio_string<ratio<N>>><>>>>>>>>>>>>> Для тех
Например, ratio
, которые соответствуют префиксу SI, соответствует международно признанному префиксу, хранящемуся как basic_string<CharT>
>.ratio_string<mega, char>::prefix()
возвратит string("mega")
. Для тех ratio
s, которые соответствуют префиксу SI symbol
, соответствует международно признанному символу, хранящемуся как basic_string<CharT>
>. Например, ratio_string<mega, char>::symbol()
возвратит string("M")
. Для всех остальных ratio
s, как префикс()
и symbol()
возвратить basic_string
, содержащий "[ratio::num/ratio>den>>>>.
ratio_string<ratio<N, D>, CharT>
определяется только для четырех типов символов:
char
: UTF-8char16_t
: UTF-16char32_t
: UTF-32wchar_t
: UTF-16 (если wchar_t составляет 16 бит) или UTF-32Когда персонаж является char, UTF-8 будет использоваться для кодирования имен. Когда персонаж char16_t
, UTF-16 будет использоваться для кодирования имен. Когда персонаж char32_t
, UTF-32 будет использоваться для кодирования имен. Когда персонаж wchar_t
, кодирование будет UTF-16, если wchar_t
составляет 16 бит, а в противном случае UTF-32.
символ
(Greek mu или μ) для микро определяется по Unicode на U+00B5.
Примеры:
#include <boost/ratio/ratio_io.hpp> #include <iostream> int main() { using namespace std; using namespace boost; cout << "ratio_string<deca, char>::prefix() = " << ratio_string<deca, char>::prefix() << '\n'; cout << "ratio_string<deca, char>::symbol() = " << ratio_string<deca, char>::symbol() << '\n'; cout << "ratio_string<giga, char>::prefix() = " << ratio_string<giga, char>::prefix() << '\n'; cout << "ratio_string<giga, char>::symbol() = " << ratio_string<giga, char>::symbol() << '\n'; cout << "ratio_string<ratio<4, 6>, char>::prefix() = " << ratio_string<ratio<4, 6>, char>::prefix() << '\n'; cout << "ratio_string<ratio<4, 6>, char>::symbol() = " << ratio_string<ratio<4, 6>, char>::symbol() << '\n'; }
Выход будет
ratio_string<deca, char>::prefix() = deca ratio_string<deca, char>::symbol() = da ratio_string<giga, char>::prefix() = giga ratio_string<giga, char>::symbol() = G ratio_string<ratio<4, 6>, char>::prefix() = [2/3] ratio_string<ratio<4, 6>, char>::symbol() = [2/3]
С точки зрения класса _ratio как Rational Constant мы можем смешивать _ratio<> и Boost.MPL Integral Constants в том же выражении, что и в
typedef mpl::times<int_<5>, giga>::type _5giga; // _5giga::num == 5000000000, _5giga::den == 1 typedef mpl::times<int_<5>, nano>::type _5nano; // _5nano::num == 1, _5nano::den == 200000000
Этот пример иллюстрирует использование boost::chrono::duration
Типы Boost.Ratio инфраструктура и философия дизайна.
Давайте начнем с определения шаблона класса длина
, который имитирует boost::chrono::duration
, который представляет собой продолжительность времени в различных единицах, но ограничивает представление ДП
и использует Boost.Ratio для преобразования единицы длины:
template <class Ratio> class length { private: double len_; public: typedef Ratio ratio; length() : len_(1) {} length(const double& len) : len_(len) {} template <class R> length(const length<R>& d) : len_(d.count() * boost::ratio_divide<Ratio, R>::type::den / boost::ratio_divide<Ratio, R>::type::num) {} double count() const {return len_;} length& operator+=(const length& d) {len_ += d.count(); return *this;} length& operator-=(const length& d) {len_ -= d.count(); return *this;} length operator+() const {return *this;} length operator-() const {return length(-len_);} length& operator*=(double rhs) {len_ *= rhs; return *this;} length& operator/=(double rhs) {len_ /= rhs; return *this;} };
Вот небольшая выборка единиц длины:
typedef length<boost::ratio
<1> > meter; // set meter as "unity" typedef length<boost::centi
> centimeter; // 1/100 meter typedef length<boost::kilo
> kilometer; // 1000 meters typedef length<boost::ratio
<254, 10000> > inch; // 254/10000 meters
Обратите внимание, что, поскольку параметр шаблона длина
на самом деле является типовым типом соотношения, так что мы можем использовать бустер::ratio, позволяющий более сложные единицы длины:
typedef length<boost::ratio_multiply<boost::ratio
<12>, inch::ratio
>::type> foot; // 12 inchs typedef length<boost::ratio_multiply<boost::ratio
<5280>, foot::ratio
>::type> mile; // 5280 feet
Теперь нам нужно определение секунд на основе плавающей точки:
typedef boost::chrono::duration<double> seconds; // unity
Мы даже можем поддерживать продолжительность субнаносекунд:
typedef boost::chrono::duration<double, boost::pico
> picosecond; // 10^-12 seconds typedef boost::chrono::duration<double, boost::femto
> femtosecond; // 10^-15 seconds typedef boost::chrono::duration<double, boost::atto
> attosecond; // 10^-18 seconds
Наконец, мы можем написать доказательство концепции библиотеки SI-подразделений, жестко проводной для метров и плавающих точечных секунд, хотя она примет другие единицы:
template <class R1, class R2> class quantity { double q_; public: typedef R1 time_dim; typedef R2 distance_dim; quantity() : q_(1) {} double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity<boost::ratio
<1>, boost::ratio
<0> > { double q_; public: quantity() : q_(1) {} quantity(seconds d) : q_(d.count()) {} // note: only User1::seconds needed here double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity<boost::ratio
<0>, boost::ratio
<1> > { double q_; public: quantity() : q_(1) {} quantity(meter d) : q_(d.count()) {} // note: only User1::meter needed here double get() const {return q_;} void set(double q) {q_ = q;} }; template <> class quantity<boost::ratio
<0>, boost::ratio
<0> > { double q_; public: quantity() : q_(1) {} quantity(double d) : q_(d) {} double get() const {return q_;} void set(double q) {q_ = q;} };
Это позволяет создавать некоторые полезные типы блоков на основе SI:
typedef quantity<boost::ratio
<0>, boost::ratio
<0> > Scalar; typedef quantity<boost::ratio
<1>, boost::ratio
<0> > Time; // second typedef quantity<boost::ratio
<0>, boost::ratio
<1> > Distance; // meter typedef quantity<boost::ratio
<-1>, boost::ratio
<1> > Speed; // meter/second typedef quantity<boost::ratio
<-2>, boost::ratio
<1> > Acceleration; // meter/second^2
Чтобы сделать количество полезным, мы должны иметь возможность делать арифметические:
template <class R1, class R2, class R3, class R4> quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> operator/(const quantity<R1, R2>& x, const quantity<R3, R4>& y) { typedef quantity<typename boost::ratio_subtract<R1, R3>::type, typename boost::ratio_subtract<R2, R4>::type> R; R r; r.set(x.get() / y.get()); return r; } template <class R1, class R2, class R3, class R4> quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> operator*(const quantity<R1, R2>& x, const quantity<R3, R4>& y) { typedef quantity<typename boost::ratio_add<R1, R3>::type, typename boost::ratio_add<R2, R4>::type> R; R r; r.set(x.get() * y.get()); return r; } template <class R1, class R2> quantity<R1, R2> operator+(const quantity<R1, R2>& x, const quantity<R1, R2>& y) { typedef quantity<R1, R2> R; R r; r.set(x.get() + y.get()); return r; } template <class R1, class R2> quantity<R1, R2> operator-(const quantity<R1, R2>& x, const quantity<R1, R2>& y) { typedef quantity<R1, R2> R; R r; r.set(x.get() - y.get()); return r; }
Со всеми вышеперечисленными скафлляциями мы теперь можем написать пример функции безопасной физики типа:
Distance compute_distance(Speed v0, Time t, Acceleration a) { return v0 * t + Scalar(.5) * a * t * t; // if a units mistake is made here it won't compile }
Наконец, мы можем использовать то, что мы создали, даже используя продолжительность времени (User1::секунды
), а также продолжительность рабочего времени (boost::chrono::часов
). Вход может быть произвольным, хотя и безопасным по типу, единицы, выход всегда в единицах SI. (Полная библиотека единиц будет поддерживать другие подразделения, конечно.)
int main() { typedef boost::ratio
<8, BOOST_INTMAX_C(0x7FFFFFFFD)> R1; typedef boost::ratio
<3, BOOST_INTMAX_C(0x7FFFFFFFD)> R2; typedef User1::quantity<boost::ratio_subtract<boost::ratio
<0>, boost::ratio
<1> >::type, boost::ratio_subtract<boost::ratio
<1>, boost::ratio
<0> >::type > RR; typedef boost::ratio_subtract<R1, R2>::type RS; std::cout << RS::num << '/' << RS::den << '\n'; std::cout << "*************\n"; std::cout << "* testUser1 *\n"; std::cout << "*************\n"; User1::Distance d( User1::mile(110) ); User1::Time t( boost::chrono::hours
(2) ); RR r=d / t; //r.set(d.get() / t.get()); User1::Speed rc= r; User1::Speed s = d / t; std::cout << "Speed = " << s.get() << " meters/sec\n"; User1::Acceleration a = User1::Distance( User1::foot(32.2) ) / User1::Time() / User1::Time(); std::cout << "Acceleration = " << a.get() << " meters/sec^2\n"; User1::Distance df = compute_distance(s, User1::Time( User1::seconds(0.5) ), a); std::cout << "Distance = " << df.get() << " meters\n"; std::cout << "There are " << User1::mile::ratio::den << '/' << User1::mile::ratio::num << " miles/meter"; User1::meter mt = 1; User1::mile mi = mt; std::cout << " which is approximately " << mi.count() << '\n'; std::cout << "There are " << User1::mile::ratio::num << '/' << User1::mile::ratio::den << " meters/mile"; mi = 1; mt = mi; std::cout << " which is approximately " << mt.count() << '\n'; User1::attosecond as(1); User1::seconds sec = as; std::cout << "1 attosecond is " << sec.count() << " seconds\n"; std::cout << "sec = as; // compiles\n"; sec = User1::seconds(1); as = sec; std::cout << "1 second is " << as.count() << " attoseconds\n"; std::cout << "as = sec; // compiles\n"; std::cout << "\n"; return 0; }
См. исходный файл example/si_physics.cpp
Наиболее авторитетным справочным материалом для библиотеки является текущий рабочий документ Комитета по стандартам C++ (WP). 20.6 Совместное рациональное арифметическое «ратио»
От Говарда Э. Хиннанта, Уолтера Э. Брауна, Джеффа Гарланда и Марка Патерно. Является очень информативным и обеспечивает мотивацию ключевых дизайнерских решений
От Висенте Хуана Бетета Эскриба.
Статья User's Guide раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 31. Boost.Ratio 2.1.0 может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 31. Boost.Ratio 2.1.0 ::
реклама |