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)
 下面是ratio_add 的源代码

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     { };
可以知道这是经过约分之后进行的比较。


posted @ 2013-04-09 20:14  xuning2516  阅读(517)  评论(0编辑  收藏  举报