你要的东西,STL 库已经有了,叫 std::ratio ,是 C++11 标准的模板类。在 C++11 标准之后,C++委员会加入了大量高等数学相关的函数,beta函数、gamma函数、黎曼Zeta函数、球面贝塞尔函数等等,少不了优秀的先驱库 boost 的功劳。Standard library header en.cppreference.com
std::ratio_add、std::ratio_subtract、std::ratio_multiply、ratio_divide 对应加减乘除四则运算,然后分数间比较大小的函数也有。下面用 std::ratio 来做一下加减乘除运算:
#include #include
int main()
{
using two_third = std::ratio<2, 3>;
using one_sixth = std::ratio<1, 6>;
using sum = std::ratio_add;
std::cout << "2/3 + 1/6 = " << sum::num << '/' << sum::den << '\n';
using diff = std::ratio_subtract;
std::cout << "2/3 - 1/6 = " << diff::num << '/' << diff::den << '\n';
using product = std::ratio_multiply;
std::cout << "2/3 * 1/6 = " << product::num << '/' << product::den << '\n';
using quotient = std::ratio_divide;
std::cout << "(2/3) / (1/6) = " << quotient::num << '/' << quotient::den << '\n';
return 0;
}
程序输出结果:
2/3 + 1/6 = 5/6
2/3 - 1/6 = 1/2
2/3 * 1/6 = 1/9
(2/3) / (1/6) = 4/1
如果初学,不妨自己尝试写个分数类;如果在工程项目里,就用标准库里的东西。有人反馈上面是模板元编程(Template Metaprogramming),不是类,你可以自己写一个分数类,然后重载加减乘除、大小比较等操作符。然后需要熟悉一个算法,小学里的通分求最小公倍数(least common multiple),分数化简求最大公约数(greatest common divisor)。求 gcd 的算法是辗转相除法,然后根据恒等式 gcd(a, b) * lcm(a, b) = a * b,求得 lcm,希望你自己也能手写出代码。当然,这两个函数在 C++ 库里也是有的,用的首字母缩写,分别对应std::lcm、std::gcd。代码可以参考 boost::rational,C++没有把这个类集成进来成,即没有 std::rational。
编程中你会遇到的问题:std::gcd 是 C++17引入的,自己实现的话算法用递归,还是非递归实现?(小问题);
模板限制类型为有符号整形,无符号整形需要额外的数据来表示正负(C++11用static_assert,C++20可以用 requires 来限制类型);
除以值为0的分数如何处理?(根据个人需求决定是否抛异常,抛异常就不用处理特殊的数);
通分后分母表示的整数过大导致溢出了如何处理?(能约分则尽量约分)。
详细的 C++ 代码可以参考这里。为了增加健壮型,这里处理了 +0, -0, +∞, -∞, NaN这5个特殊的数,让它们符合浮点数的运算规则
0 * inf 等于 nan
0 / inf 等于 0
inf * inf 等于 inf
negative_finite_rational * +inf 等于 -inf
inf - inf 等于 nan
nan == nan 返回 false
inf == inf 返回 true
inf < inf 返回 false
另,提一下培养编程修养——英语也要抓。我见过初学者写阶乘的代码用拼音命名函数名。考虑到所有的有理数可以用分数表示,类名用有理数(Rational)还是分数(Fraction)都行,数据成员有分子(numerator),分母( denominator)。不要偷懒用a和b表示,一眼看去不知道谁是分子,谁是分母。Rational Number Library - 1.55.0www.boost.org
题目有所更改,新添加了 Java 和 Python 语言,那我也补充一下回答好了。算法都是一样的,只是用不同的语言描述而已。代码都是用英语写的。
Java 是直接支持大整数(java.math.BigInteger)和大浮点数(java.math.BigDecimal)的运算,没有直接的Rational类。BigInteger 里也提供了gcd 和 lcm 方法。
Android 的上层用 Java 语言写的,有 android.util.Rational 类表示有理数,实现了 Comparable 接口,里面有常用的静态常量0, +∞, -∞, NAN。代码有bug。有NaN参与比较的话总是失败,即应该返回false。注释“NaN is greater than the other non-NaN value”、“the other NaN is greater than this non-NaN value”是错误的。
Python 有 fractions 类,支持字符串、分子+分母构造有理数,比较丰富。比如你可以传递字符串'1/3',它就表示1/3了。可以看别人的代码学习,传送门。
参考