boost:ratio ╰半橙微兮° 2023-01-22 02:57 28阅读 0赞 # 概述 # * 日常生活中我们经常遇到小时、公斤、尺等单位,它们标记了物理量的度量。但很少有人意识到,其实用于度量物理量的数字也是有单位的:十、百、千、万是人类语言中最常见的单位,此外还有半、双、打(dozen = 12),科学研究领域则有阿伏伽德罗常数(6.022e23) * ratio完全实现了C++标准里的内容,专门用于表示数字的单位,是编译期的分数,作用类似于math.constants里的数学常量。虽然它与rational一样处理对象都是有理数,但却是两个完全不同的领域。 * ratio库位于boost名字空间,需要包含头文件`#include <boost/ratio.hpp>`。 //#define BOOST_RATIO_EXTENSIONS #include <boost/ratio.hpp> using namespace boost; * ratio库使用宏BOOST\_RATIO\_EXTENSIONS提供了一些C++标准之外的扩展功能,比如operator()、rational转换、KB/MB/GB等 ## 类摘要 ## ratio库的核心类是模板类ratio,定义很简单: template <boost::intmax_t N, boost::intmax_t D> class ratio { public: BOOST_STATIC_CONSTEXPR boost::intmax_t num = SIGN_N * ABS_N / GCD; // 分子 BOOST_STATIC_CONSTEXPR boost::intmax_t den = ABS_D / GCD; // 分母 typedef ratio<num, den> type; // 自身类型定义 }; * ratio有两个模板参数,都是整数类型,一起定义了编译期分数N/D。如果分母是1,那么第二个模板参数可以省略不必写出 * ratio主要的成员是num和den,和rational一样表示分子和分母,但不同的是它们都是静态成员,所以能够在编译期进行各种计算。 ## 基本用法 ## * ratio实际上属于模板元计算的范畴,大多数操作都是在编译期,使用比如ratio\_add、ratio\_subtract、ratio\_multyply、ratio\_divide等元函数执行编译期有理数计算。 * ratio在模板参数列表里指定两个参数,定义一个编译期的分数类型,这就是它最主要的动作。有了这个分数类型之后就可以用静态成员num和den获取分子和分母再做运算。 typedef ratio<1, 2> half; assert(half::num == 1); assert(half::den == 2); typedef ratio<12> dozen; assert(2 * dozen::num == 24); * 使用ratio时我们必须要意识到它是一个类型而不是一个变量,所以通常要配合typedef来简化名字,形式上很像是声明了一个变量,但千万不要用`.`去操作它,只能用域作用符`::`来调用它的静态成员 ## 数字单位 ## * ratio实现了C++标准里定义的全部数字单位(标准里的yocto、zepto、zetta、yotta等单位因为超过了boost::intmax\_t的范围而没有定义。"1"和"0"这两个单位是没有必要定义的) typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000000000000000000)> atto; typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000000000000000)> femto; typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000000000000)> pico; typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000000000)> nano; // 十亿分之一 typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000000)> micro; // 百万分之一 typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(1000)> milli; // 千分之一 typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(100)> centi; // 百分之一 typedef ratio<BOOST_RATIO_INTMAX_C(1), BOOST_RATIO_INTMAX_C(10)> deci; // 十分之一 typedef ratio< BOOST_RATIO_INTMAX_C(10), BOOST_RATIO_INTMAX_C(1)> deca; // 十 typedef ratio< BOOST_RATIO_INTMAX_C(100), BOOST_RATIO_INTMAX_C(1)> hecto; // 百 typedef ratio< BOOST_RATIO_INTMAX_C(1000), BOOST_RATIO_INTMAX_C(1)> kilo; // 千 typedef ratio< BOOST_RATIO_INTMAX_C(1000000), BOOST_RATIO_INTMAX_C(1)> mega; // 百万 typedef ratio< BOOST_RATIO_INTMAX_C(1000000000), BOOST_RATIO_INTMAX_C(1)> giga; // 十亿 typedef ratio< BOOST_RATIO_INTMAX_C(1000000000000), BOOST_RATIO_INTMAX_C(1)> tera; typedef ratio< BOOST_RATIO_INTMAX_C(1000000000000000), BOOST_RATIO_INTMAX_C(1)> peta; typedef ratio<BOOST_RATIO_INTMAX_C(1000000000000000000), BOOST_RATIO_INTMAX_C(1)> exa; * 在这些ratio库预定义的数字单位之外,我们也可以定义自己的单位,比如: typedef ratio<1, 2> half; // 一半 typedef ratio<1, 4> quater; // 四分之一 typedef ratio<12, 1> dozen; // 一打 typedef ratio<kilo::num*10, 1> cn_wan; // 万 typedef ratio< 1024> kibi; //KB typedef ratio< 1024*1024> mebi; //MB typedef ratio< 1024*1024*1024> gibi; //GB int main() { assert(kilo::num < kibi::num); cout << kilo::num << endl; cout << kibi::num << endl; assert(mega::num == cn_wan::num*100); } ![在这里插入图片描述][2021051713380794.png] * 我们也可以使用自定义字母值特性来简化代码。比如,下面的代码定义了`_kb`、`_gb`的数字单位,无须直接写出ratio类型,非常的方便: boost::intmax_t operator"" _kb(unsigned long long n) { return n * kibi::num; } boost::intmax_t operator"" _gb(unsigned long long n) { return n * gibi::num; } int main() { auto x = 2_gb; auto y = 10_kb; cout << x; assert(x = 2 * 100 * y); } ![在这里插入图片描述][20210517134158180.png] ## 字符串表示 ## 模板类ratio\_string可以获得ratio的字符串描述信息,它的声明是: template <class Ratio, class CharT> struct ratio_string { static std::basic_string<CharT> short_name() { return long_name();} static std::basic_string<CharT> long_name(); static std::basic_string<CharT> symbol() { return short_name();} static std::basic_string<CharT> prefix() { return long_name();} }; ratio\_string在模板参数里接受ratio和char类型,然后用静态成员函数symbol()和prefix()等输出对应的字符串形式,通常是"\[N/D\]"的形式,但对kilo、mego等预定义的ratio单位有特化版本。 template<typename R> using string_out = ratio_string<R, char>; int main() { cout << string_out<kilo>::symbol << "\t" << string_out<kilo>::prefix() << "\n"; cout << string_out<nano>::symbol << "\t" << string_out<nano>::prefix() << "\n"; cout << string_out<ratio<22, 7>>::prefix() << "\n"; } [2021051713380794.png]: /images/20221020/6a494cadd8a548c9b2e82a4336fe1023.png [20210517134158180.png]: /images/20221020/8555ddecb0da41fd9808416112275d04.png
还没有评论,来说两句吧...