【问题标题】:Binomial coefficient二项式系数
【发布时间】:2023-04-30 07:34:01
【问题描述】:

'简单'的问题,计算二项式系数的最快方法是什么? - 一些线程算法?

我正在寻找提示 :) - 不是实现 :)

【问题讨论】:

  • 不准确且仅适用于有限的输入范围?我认为您应该扩展一下您的要求。例如,如果您只对机器大小的整数感兴趣,那是一回事,任意大小的整数则是另一回事。
  • Here 是您可能感兴趣的内容。 Numerical Recipes 也可能有用。
  • 好吧,让我们把它限制为 java doubles? :) - 在整数级别上准确
  • 您可能会发现斯特林的近似值很有用。

标签: multithreading algorithm complexity-theory binomial-coefficients binomial-cdf


【解决方案1】:

我认为最快的方法是从表中读取它们而不是计算它们。

您对使用双精度表示的整数精度的要求意味着 C(60,30) 几乎太大了,大约为 1e17,因此(假设您希望所有 m 都具有 C(m,n)一些限制,并且所有 n

【讨论】:

    【解决方案2】:

    根据下面的等式(来自wikipedia),最快的方法是将范围 i=1,k 拆分为线程数,给每个线程一个范围段,每个线程将最终结果更新为锁。 “学术方式”是将范围划分为任务,每个任务都计算(n - k + i)/i,然后无论你有多少线程,它们都在循环中运行,要求下一个任务。第一个更快,第二个是……学术。

    编辑:进一步解释 - 在这两种方式中,我们都有一些任意数量的线程。通常线程数等于处理器内核数,因为添加更多线程没有任何好处。两种方式之间的区别在于这些线程在做什么。

    在第一种方式中,每个线程被赋予 N、K、I1 和 I2,其中 I1 和 I2 是 1..K 范围内的段。然后每个线程都有它需要的所有数据,因此它计算它的部分结果,并在完成后更新最终结果。

    在第二种方式中,每个线程都被赋予 N、K,并访问一些从 1 到 K 计数的同步计数器。然后每个线程从这个共享计数器中获取一个值,计算结果的一部分,更新最终结果,并在此循环,直到计数器通知线程没有更多项目。如果碰巧某些处理器内核比其他处理器内核更快,那么第二种方法将使所有内核得到最大利用。第二种方式的缺点是过多的同步会一直有效地阻塞 20% 的线程。

    【讨论】:

    • 哪一部分?也许您应该推迟标记正确答案,直到您确认答案确实正确。
    【解决方案3】:

    提示:您希望尽可能少地进行乘法运算。公式为n! / (k! * (n-k)!)。您应该少于2m 乘法,其中mkn-k 的最小值。如果你想处理(相当)大的数字,你应该使用一个特殊的类来表示数字(例如 Java 有 BigInteger)。

    【讨论】:

      【解决方案4】:

      如果最终结果可以在机器中本机表达、不涉及乘法/分解、易于并行化并推广到 BigInteger 类型,那么这是一种永不溢出的方法:

      首先注意二项式系数满足以下条件:

      .

      这产生了用于计算系数的简单递归:基本情况是 和 ,两者都是 1。

      子调用的单个结果是整数,如果 \binom{n}{k} 可以用 int 表示,它们也可以;所以,溢出不是问题。

      简单地实现,递归会导致重复的子调用和指数运行时间。

      这可以通过缓存中间结果来解决。有 n^2 个子问题,可以在 O(1) 时间内组合,产生 O(n^2) 复杂度界限。

      【讨论】:

        【解决方案5】:

        这个答案用 Python 计算二项式:

        def h(a, b, c):
            x = 0
            part = str("=") 
            while x < (c+1):
                nCr = math.comb(c,x)
                part = part+'+'+str(int(a**(c-1))*int(b**x)*int(nCr)+'x^'+str(x)
                x = x+1
            print(part) 
            
            h(2,6,4)
        

        【讨论】: