我很确定这是这个问题的正确网站,但如果它更适合那里,请随意将其移至其他堆栈交换网站。
假设您有一个分数a1/d1 + a2/d2 + … + an/dn
的总和。您想要计算一个公共分子和分母,即将其重写为p/q
。我们有公式
p = a1*d2*…*dn + d1*a2*d3*…*dn + … + d1*d2*…d(n-1)*an
q = d1*d2*…*dn.
计算这些内容的最有效方法是什么,尤其是p
?你可以看到,如果你天真地计算它,即使用我上面给出的公式,你会计算很多冗余的东西。例如,您将计算d1*d2
n-1
次。
我的第一个想法是迭代计算d1*d2
,d1*d2*d3
,...和dn*d(n-1)
,dn*d(n-1)*d(n-2)
,......但即使这样效率也很低,因为你最终会计算乘法在“中间”两次(例如,如果n
足够大,您将计算两次d3*d4
。
我确信这个问题可以用某种图形理论或组合学来表达,但我还没有研究过足够的东西以便对它有一个良好的感觉。
还有一个注意事项:我不关心取消,只是最有效的繁殖方式。
更新:
我应该知道stackoverflow上的人会假设这些是数字,但我已经习惯了我的用例,我忘了提这个。
我们不能只从每个术语中“划分”an
。这里的用例是一个符号系统。实际上,我正在尝试在SymPy computer algebra system中修复一个名为.as_numer_denom()
的函数,该函数目前以天真的方式计算它。请参阅corresponding SymPy issue。
划分事情有一些问题,我想避免。首先,不能保证事情会取消。这是因为在数学上,(a*b)**n != a**n*b**n
一般来说(如果a
和b
是正数,但是例如,如果a == b ==-1
和n == 1/2
,则得到(a*b)**n == 1**(1/2) == 1
1}}但是(-1)**(1/2)*(-1)**(1/2) == I*I == -1
)。所以我认为假设除以an
将在表达式中取消它(这可能实际上是没有根据的,我需要检查代码的作用)并不是一个好主意。
其次,我还想将此算法应用于计算有理函数的总和。在这种情况下,这些项将自动乘以一个多项式,并且“除去”每个an
将涉及应用多项式除法算法。你可以看到,在这种情况下,你真的想要首先计算最有效的乘法。
更新2:
我认为我对取消象征性术语的担忧可能毫无根据。 SymPy不会自动取消x**n*x**(m - n)
之类的内容,但我认为通过乘法组合的任何指数也会通过除法组合,因此权力应该取消。
常量会自动分配添加内容,例如:
In [13]: 2*(x + y)*z*(S(1)/2)
Out[13]:
z⋅(2⋅x + 2⋅y)
─────────────
2
但这是第一个bug,第二个永远不会成为问题(我认为),因为1/2
会被1
和2
分解为算法每个术语的分子和分母。
尽管如此,我仍然想知道如何在不从每个术语“分割”di
的情况下做到这一点,这样我就可以有一个有效的算法来总结合理的函数。
答案 0 :(得分:3)
计算两个新数组:
第一个包含左侧的部分倍数:l[0] = 1, l[i] = l[i-1] * d[i]
第二个包含右侧的部分倍数:r[n-1] = 1, r[i] = d[i] * r[i+1]
在这两种情况下,1
都是你工作的戒指的乘法身份。
然后,您的每个字词都位于顶部,t[i] = l[i-1] * a[i] * r[i+1]
这假设乘法是关联的,但它不一定是可交换的。
作为第一个优化,您实际上不必将r
创建为数组:您可以执行第一次传递来计算所有l
值,并累积r
在第二次(向后)传递期间的值以计算加数。无需实际存储r
值,因为您按顺序使用每个值。
在你的问题中,你说这会计算d3*d4
两次,但事实并非如此。它确实将两个不同的值乘以d4
(一个是右乘,另一个是左乘),但这并不是一个重复的操作。无论如何,对于在非交换乘法或非场环中不起作用的另一种方法,乘法的总数约为4*n
,而2*n
乘法和n
除法。
答案 1 :(得分:2)
如果你想在上面的表达式中计算p
,一种方法是将所有分母相乘(在O(n)中,其中n是分数的数量),让这个值为D
。然后,迭代所有分数,对于每个分数,分子a i 和分母d i ,计算 i * D / d <子> I 子>。最后一个术语等于分数的分子和除了它自己之外的所有分母的乘积。这些术语中的每一个都可以在O(1)时间内计算(假设您正在使用硬件乘法,否则可能需要更长时间),并且您可以在O(n)时间内对它们进行求和。
这给出了一个O(n)时算法,用于计算新分数的分子和分母。
答案 2 :(得分:2)
不是一次性添加n
商,而是使用成对添加商。
如果事物在部分和中抵消,则数字或多项式保持较小,这使计算更快。
您可以避免多次计算同一产品的问题。
您可以尝试以某种方式订购添加内容,以便更有可能取消(可能先添加小分母的商数?),但我不知道这是否值得。
如果你从头开始,这更容易实现,但我不确定它是否适合替代SymPy中有问题的例程。
修改:为了使其更明确,我建议将a1/d1 + a2/d2 + … + an/dn
计算为(…(a1/d1 + a2/d2) + … ) + an/dn
。
答案 3 :(得分:0)
我还指出,你可以手动筛选出共同的分母,并将这些分组合并而不是乘法。