C++ ratio
C++11提供了compile_time fractions and compile-time rational arithmetic support。支持编译时常量。
头文件 <ratio>
来看ratio是怎么定义的
00152 template<intmax_t _Num, intmax_t _Den = 1> 00153 struct ratio 00154 { 00155 static_assert(_Den != 0, "denominator cannot be zero"); 00156 static_assert(_Num >= -__INTMAX_MAX__ && _Den >= -__INTMAX_MAX__, 00157 "out of range"); 00158 00159 // Note: sign(N) * abs(N) == N 00160 static constexpr intmax_t num = 00161 _Num * __static_sign<_Den>::value / __static_gcd<_Num, _Den>::value; //是一个静态常量成员变量,注意看他的初始化是在类的定义里面实现的但是在类的外面还是要声明,可以通过类名直接进行访问 00162 00163 static constexpr intmax_t den = 00164 __static_abs<_Den>::value / __static_gcd<_Num, _Den>::value; //可以看到这个最终的值是经过约分的,其中是gcd求得是两个数的最大公约数 00165 00166 typedef ratio<num, den> type; 00167 }; 00168 00169 template<intmax_t _Num, intmax_t _Den> 00170 constexpr intmax_t ratio<_Num, _Den>::num; //ratio的成员函数 00171 00172 template<intmax_t _Num, intmax_t _Den> 00173 constexpr intmax_t ratio<_Num, _Den>::den;
通过constexpr实现了compile_time 的属性。是一个compile-time constants,可以当成常量来使用。是一个具体类(还有一个具体类pair)。ratio types are used as template parameters for duration objects
来看看一个调用的例子
typedef ratio<5,3> FiveThirds; //注意这是一个类型
cout<<FiveThirds::num<<"/"<<FiveThirds::den;
ratio<5,3>::type one;
cout<<FiveThirds::num<<"/"<<FiveThirds::den;
typedef ratio<25,15> AlsoFiveThirds;
cout<<AlsoFiveThirds::num<<"/"<<AlsoFiveThirds::den;
ratio<25,15> two; //注意这是一个对象
cout<<two.num<<"/"<<two.den<<endl; //5/3
//ratio<5,0> three; //error
//提供如下的操作方法
(C++11)
|
adds two ratio objects at compile-time (class template) |
(C++11)
|
subtracts two ratio objects at compile-time (class template) |
(C++11)
|
multiplies two ratio objects at compile-time (class template) |
(C++11)
|
divides two ratio objects at compile-time (class template) |
00175 /// ratio_add 00176 template<typename _R1, typename _R2> 00177 struct ratio_add //还是采用结构体的形式实现,因此他返回的类型是ratio<> 00178 { 00179 private: 00180 static constexpr intmax_t __gcd = 00181 __static_gcd<_R1::den, _R2::den>::value; 00182 static constexpr intmax_t __n = __safe_add< 00183 __safe_multiply<_R1::num, (_R2::den / __gcd)>::value, 00184 __safe_multiply<_R2::num, (_R1::den / __gcd)>::value>::value; 00185 00186 // The new numerator may have common factors with the denominator, 00187 // but they have to also be factors of __gcd. 00188 static constexpr intmax_t __gcd2 = __static_gcd<__n, __gcd>::value; 00189 00190 public: 00191 typedef ratio<__n / __gcd2, 00192 __safe_multiply<_R1::den / __gcd2, _R2::den / __gcd>::value> type; 00193 00194 static constexpr intmax_t num = type::num; 00195 static constexpr intmax_t den = type::den; 00196 }; 00197 00198 template<typename _R1, typename _R2> 00199 constexpr intmax_t ratio_add<_R1, _R2>::num; 00200 00201 template<typename _R1, typename _R2> 00202 constexpr intmax_t ratio_add<_R1, _R2>::den;来看看这里的具体的调用。这里实现和VC2012略有不同。但是返回的都是ratio<>,因此静态成员产生的是相应的类型。
ratio_add<FiveThirds,AlsoFiveThirds>::type three; cout<<three.num<<"/"<<three.den<<endl;
下面看看ratio提供的关系运算
/// ratio_equal 00270 template<typename _R1, typename _R2> 00271 struct ratio_equal 00272 : integral_constant<bool, _R1::num == _R2::num && _R1::den == _R2::den> //返回的类型是true_value or false_type 00273 { };
ratio_equal<FiveThirds,AlsoFiveThirds>::type requal; cout<<boolalpha<<requal.value<<endl; //输出false vs2012 (libstdC++是要输出true的)这里有所不同下面有具体的讲解 cout<<ratio_equal<ratio<5,3>,ratio<5,3>>::value<<endl; //输出true
在vc2012 下面第一个输出false(?),可以看到
// CLASS TEMPLATE ratio_equal template<class _R1, class _R2> struct ratio_equal; template<intmax_t _N1, intmax_t _D1, intmax_t _N2, intmax_t _D2> struct ratio_equal<ratio<_N1, _D1>, ratio<_N2, _D2> > : integral_constant<bool, _N1 == _N2 && _D1 == _D2> { // tests if ratio == ratio };它这里没有进行约分,不知道这是基于什么考虑。
但是在libstdC++里面我们可以看到
/// ratio_equal 00270 template<typename _R1, typename _R2> 00271 struct ratio_equal 00272 : integral_constant<bool, _R1::num == _R2::num && _R1::den == _R2::den> 00273 { };可以知道这是经过约分之后进行的比较。