如何比较有理数?

时间:2010-11-26 15:59:21

标签: algorithm math

这是一个家庭作业问题。给定具有两个整数字段(分子和分母)的类“Rational”,编写一个函数来比较两个“Rational”实例。设r1 = a/br2 = c/d。简单的解决方案是比较a*db*c。我们可以做得更好吗?

6 个答案:

答案 0 :(得分:4)

在一般情况下,没有。如果你希望进行大量的比较,初步处理步骤可以处理所有事情的规范化(通过将分子和分母除以它们的gcd,并使分母为正),以便相等比较将比较a = c和b = d,但计算a * d = b * c肯定不会以任何方式禁止。

答案 1 :(得分:4)

如果您需要复杂的解决方案,请将两个分数中的每一个转换为连续分数(使用GCD算法的变体)。这个简单的算法一次生成一个整数。比较两个部分连续分数中的每对整数。如果它们不同,请退出。否则生成下一对并继续,而有更多。 对于有理数,序列是有限的,因此很快就会终止。 我相信这是a,b,c,d很大的最佳方法。

已经证明,所有平方根非理性的连续分数扩张是重复出现的。所以你也可以使用它来比较那些非理性,即使它们的二进制计算机表示会给你一个错误的结果(由于截断)。 这意味着只要您检测到模式中的重复,就可以终止,证明两个非理性的相等。

答案 2 :(得分:3)

通常分支的成本高于乘法的成本,因此除了那个之外,不值得尝试。如果用整数表示int32,则提升为int64以执行乘法运算;如果你的意思是更大的整数,那么你需要使用通常的机制来管理乘法,此时关于分支的假设可能会失效。

答案 3 :(得分:2)

从我的观点来看,如果允许负数,那么简单的解决方案是不正确的:

r1=1/3b=1/(-3)怎么样都应该是正确的有理数。当然,从数学角度来看,它认为: 1 /( - 3)< 1/3

但是,建议的解决方案会产生1*3 > 1*(-3),导致1/3 < 1/(-3)的错误解决方案。

我刚刚在Scala课程中遇到了这个问题:-)但我仍然没有很好的解决方案。

也许,像往常一样有助于调查BOOST-Library:它说:

  

比较合理操作执行两个双倍大小的GCD操作,两个额外的添加和减少,以及最坏情况下的三个比较。 (GCD操作是双倍大小的,因为它们是零碎的,临时商保留并进行比较,而直接GCD功能只保留并比较余数。)

http://www.boost.org/doc/libs/1_55_0/libs/rational/rational.html

到目前为止,我还没有机会调查该代码。

干杯, 菲利克斯

与此同时,我看了一下Boost代码,就像Liberius在上面的回答中描述的那样。 https://stackoverflow.com/a/4288890/2682209 所以这绝对是&#34;正确&#34; (但很麻烦)的方式。

答案 4 :(得分:1)

我不喜欢a*d b*c解决方案,因为如果某些分子和分母很大,它可能会导致不必要的整数溢出。虽然我没有更好的解决方案。

答案 5 :(得分:0)

如果你正在使用Java,那么你可以在遇到溢出时使用java.math.BigInteger类;否则,您可以实现自己的via byte-arrays。