boost:rational 不念不忘少年蓝@ 2023-01-22 02:49 30阅读 0赞 # 概述 # > * 科学计算的基础是数字运算,C++语言内建了int/float/double,分别用于支持有限精度的整数和小鼠,C++标准库提供了complex,支持复数的概念。但是,数学中另一种非常重要的库被遗落了,那就是有理数(分数) > * boost.rational库实现了有理数,补充了C++的数字概念。它基于C++的内建整数类型,数字运算时没有精度损失,可以应用于金融财务等需要准确值的领域 > * 注:boost有另一个库ratio,它实现了C++标准定义的编译期有理数 rational位于名字空间boost,需要包含头文件`<boost/rational.hpp>` #include <boost/rational.hpp> using namespace boost; ## 类摘要 ## template <typename IntType> class rational { // Class-wide pre-conditions BOOST_STATIC_ASSERT( ::std::numeric_limits<IntType>::is_specialized ); // Helper types typedef typename boost::call_traits<IntType>::param_type param_type; struct helper { IntType parts[2]; }; typedef IntType (helper::* bool_type)[2]; public: typedef IntType int_type; rational(); // 默认构造,相当于0 rational(param_type n) ; // 整数构造,相当于n/1 rational(param_type n, param_type d); // 分数构造,相当于n/d rational& operator=(param_type n) { return assign(n, 1); } // 赋值 rational& assign(param_type n, param_type d); IntType numerator() const { return num; } // 获取内部的分子分母 IntType denominator() const { return den; } //操作符重载 rational& operator+= (const rational& r); rational& operator-= (const rational& r); rational& operator*= (const rational& r); rational& operator/= (const rational& r); rational& operator+= (param_type i); rational& operator-= (param_type i); rational& operator*= (param_type i); rational& operator/= (param_type i); const rational& operator++(); const rational& operator--(); bool operator!() const { return !num; } operator bool_type() const; // bool类型转换 bool operator< (const rational& r) const; bool operator== (const rational& r) const; bool operator< (param_type i) const; bool operator> (param_type i) const; bool operator== (param_type i) const; }; rational类内部把有理数用"分子/分母"的形式保存,并运算时使用最大公约数、最小公倍数等操作加以恰当的规范化。 类似标准库的复数类,rational需要使用模板定义基本整数类型: rational<int> pi(22, 7); //圆周率的”约率“ ## 创建与赋值 ## rational有三种形式的构造函数: rational<int> a; rational<int> b(20); rational<int> c(31415, 10000); cout << "a = " << a << "\n" << "b = " << b << "\n" << "c = " << c << "\n"; ![在这里插入图片描述][20210517114522941.png] rational重载了operator=,可以直接从另一个整数赋值,或者使用成员函数assign接受”分子/分母“形式的两个整数参数赋值。 rational<int> r; //r = 0; cout << r << "\t"; r = 0x31; // r = 0x31(16进制)或者r=49(十进制) cout << r << "\t"; r.assign(7, 9); cout << r << "\t"; ![在这里插入图片描述][20210517115259182.png] 因为有理数是分数,是以除法来表示的数,所以rational的分母不能是0。当构造、赋值或者其他操作导致除以0的情形时,rational会抛出bad\_rational异常。 ## 基本运算 ## rational实现了完整的算术操作,包括基本的加减乘除、递增递减和各种比较运算,其语法与内建类型没有任何区别: rational<int> a(3),b(65534),c(22,7); b += a; c -= a; if (c >= 0) { c = c * b; ++a; } assert(a == 4); ## 类型转换 ## rational也可以在bool语境中直接隐式转换为bool类型,当它值是0是为false,否则为true。 rational也重载了operator!,以相反的规则转换为bool类型 rational<int> r(10); if (r) { r -= 10; } assert(!r); 除了bool以外,rational不能隐式转换到其他任何类型(即使是分母为1的有理数转换到整数),而必须使用rational\_cast函数: rational<int> r(2718, 1000); cout << rational_cast<int>(r) << endl; cout << rational_cast<double>(r) << endl; ![在这里插入图片描述][20210517123804318.png] ## 输入输出 ## rational重载了输入输出操作符,可以直接与IO流配合工作,格式为用/分隔两个整数 rational<int> r; cin >> r; cout << ++r; ![在这里插入图片描述][20210517124044213.png] ## 分子和分母 ## rational的成员函数numerator()和denominator()可以直接访问有理数对象的分子和分母,但返回的是个右值,只可以读不可以写: rational<int> r(22,7); cout << r.numerator() << ":" << r.denominator() << "=" << rational_cast<double>(r); cout << endl; ![在这里插入图片描述][20210517124245871.png] ## 其他 ## ### 配合数学函数工作 ### rational没有实现到float/double的隐式转换,所以不能直接使用sqrt()、pow()等标准C函数(abs()除外,因为rational实现了对它的重载) 如果要对rational对象实施这些数学运算,必须先使用rational\_cast显式转换为double、float等才可以: rational<int> a(-1414,1000), pi(314, 100); cout << "abs=" << abs(a) << endl; cout << pow(rational_cast<double>(a), 2) << endl; cout << cos(rational_cast<double>(pi)) << endl; ### 精确度 ### rational虽然能够精确的处理有理数,但不能保证无限制精度,它的精确度完全取决于模板参数IntType。rational的最大精度度是`numeric_limits<IntType>::max()`,最小精确度是`1.0/numeric_limits<IntType>::max()` 注:如果使用高精度数字库boost.multiprecision提供的任意精确度整数类型cpp\_int,那么rational就可以获得无限的精确度。 另外,rational没有针对numeric\_limits提供特化版本,因此无法对它求数值极限,所有`numeric_limits<rational<IntType>>`但是无意义的,因为: assert(numeric_limits<rational<IntType>>::is_specialized == true); 总成立。 ### 最大公约数和最小公倍数 ### rational还提供了两个工具函数:最大公约苏gcd()和最小公倍数lcm: #if BOOST_CONTROL_RATIONAL_HAS_GCD template <typename IntType> IntType gcd(IntType n, IntType m) { // Defer to the version in Boost.Math return math::gcd( n, m ); } template <typename IntType> IntType lcm(IntType n, IntType m) { // Defer to the version in Boost.Math return math::lcm( n, m ); } 使用方法: #include <iostream> using namespace std; #include <boost/rational.hpp> using namespace boost; #include <boost/format.hpp> void case1() { int a = 37, b = 62; format fmt("gcd(%1%, %2%) = %3%. lcm(%1%, %2%) = %4%\n"); cout << fmt % a % b % gcd(a,b) % lcm(a,b); } int main() { case1(); } ![在这里插入图片描述][20210517125501231.png] [20210517114522941.png]: /images/20221020/9cfe246cc9c54981a60d686fecc74447.png [20210517115259182.png]: /images/20221020/9d2be274248444a89fcf1a244859352e.png [20210517123804318.png]: /images/20221020/4322ea1fc2d34d4b908de71782a9ee26.png [20210517124044213.png]: /images/20221020/cc6a206ea26b4b139af93da238fdfd42.png [20210517124245871.png]: /images/20221020/b7c29fe306e94a3488b0873eae488803.png [20210517125501231.png]: /images/20221020/da847ba2b375432eb8ea11b11a393f3e.png
还没有评论,来说两句吧...