声明:原文链接 C++(标准库)分数运算(ratio库)
一、ratio概述
- 自C++11起,C++标准库提供了一个接口允许你具体指定编译期分数,并允许对它们执行编译期运算
- 以下摘自[N266:Chrnon]并略有改动:
二、ratio的实现
- ratio由<ratio>提供,其定义如下:
- type:产出相应类型,其也是一个ratio<>,其返回自身,可以直接使用域访问父访问
- num:分子
- den:分母,默认为1
- 其所有成员都是public的
- intmax_t是个带正负号的整数类型,其有能力表现出任何带正负号的整数,其被设计于<cstdint>或<stdint.h>内,至少具备64bit
演示案例
int main()
{
typedef ratio<5, 3> FiveThirds;
std::cout << FiveThirds::num << "/" << FiveThirds::den << std::endl;
typedef ratio<25, 15> AlsoFiveThirds;
std::cout << AlsoFiveThirds::num << "/" << AlsoFiveThirds::den << std::endl;
typedef ratio<42,42> one;
std::cout << one::num << "/" << one::den << std::endl;
typedef ratio<0> zero; //分母默认为1
std::cout << zero::num << "/" << zero::den << std::endl;
typedef ratio<7, -3> Neg1; //-号会被移动到分子身上
std::cout << Neg1::num << "/" << Neg1::den << std::endl;
typedef ratio<-7, 3> Neg2; //分子的-号保持不变
std::cout << Neg2::num << "/" << Neg2::den << std::endl;
typedef ratio<-7, -3> Neg3; //分子分母的-号都会消失
std::cout << Neg3::num << "/" << Neg3::den << std::endl;
}
三、ratio提供的操作
基本运算符
- 分数的+、-、*、/分别被定义为ratio_add、ratio_substract、ratio_multiply、ratio_divide。它们的返回值也是一个ratio<>
- 演示案例:
type返回的一个是ratio<>,2/7+2/6=13/21
typedef std::ratio_add<std::ratio<2, 7>, std::ratio<2, 6>>::type test;
std::cout << test::num << "/" << test::den << std::endl
分数比较
- 其他的一些操作用来比较两个ratio类型。它们的返回值也是true_type或false_type,其成员value返回true或false(true_type、false_type在前面文章介绍过:https://blog.csdn.net/qq_41453285/article/details/105454812)
- 演示案例:
std::cout << boolalpha;
std::cout << std::ratio_equal<std::ratio<1, 3>, std::ratio<1, 3>>::value << std::endl;
std::cout << std::ratio_equal<std::ratio<2, 3>, std::ratio<1, 3>>::value << std::endl;
std::cout << std::ratio_greater<std::ratio<2, 3>, std::ratio<1, 3>>::value << std::endl;
四、使用ratio的一些注意事项
- 关于分母的一些注意事项:
- ratio定义时,其分母不能定义为0,否则编译不通过
- ratio定义时,如果不填分母,默认为1
- 关于负号(-)的一些注意事项:
- 如果分子无-号,分母有-号,分母的-号会被移动到分子身上
- 如果分子有-号,分母无-号,则分子的-号保持不动
- 如果分子分母都有-号,则-号都被消除
- 分子可以为0
- ratio会自动对分子和分母进行约分
演示案例
- ratio会捕捉所有差错,例如分母为0、溢出等等。因此下面的无法编译通过
//无法编译通过,因为1/max乘以1/2会导致溢出,分母超过了其类型所能涵盖的极限
std::ratio_multiply<std::ratio<1, std::numeric_limits<long long>::max()>, std::ratio<1, 2>>::type;
- 与上面同理,下面的表达式也无法通过编译,因为其除以了0:
typedef ratio<5, 3> FiveThirds;
typedef ratio<0> zero; //分子为0,分母默认为1
std::ratio_divide<FiveThirds, zero>::type;
- 但是下面的可以编译通过,因为下面只使用了ratio_divide<>,却没有实例化一个ratio<>对象,因此编译器检测不出来
typedef ratio<5, 3> FiveThirds;
typedef ratio<0> zero;
std::ratio_divide<FiveThirds, zero>; //只调用了ratio_divide,却没有实例化出任何ratio对象
五、预定义的ratio单位
- ratio程序库预先定义好了很多ratio单位,可以直接使用。如下图所示:
- 下图中的“optional”代表,只有“当它们可被intmax_t表达时”才被定义
- 演示案例:
typedef std::ratio<1, 1000000000LL> test;
std::cout << test::num << "/" << test::den << std::endl;
typedef std::nano _nano;
std::cout << _nano::num << "/" << _nano::den << std::endl;
- 这个演示案例也使得我们可以比较方便的指出纳秒