c ++中较大值的数学计算[重复]

Posted

技术标签:

【中文标题】c ++中较大值的数学计算[重复]【英文标题】:mathematical calculations for larger values in c++ [duplicate] 【发布时间】:2014-11-21 10:50:26 【问题描述】:

这是一个非常简单的程序,有 t 个测试用例,我们必须找到 nCr=n!/r!*(n-r)!。 所以它适用于较小的值,如 20C2,但不适用于较大的值,如 100C10。它给出 32C2=-6 ,100C10 浮点异常。 如何使它为 1注意:我不是要求 long double 或不想将其更改为 float。答案应该类似于 100C10 = 17310309456440 类似 989C45=?

#include<iostream>
using namespace std;
long long int fact(long long int num);
int main()

int t;
cin>>t;
long long int n[1000],r[1000],c[1000];
for(int i=0;i<t;i++)

cin>>n[i];
cin>>r[i];

for(int i=0;i<t;i++)

c[i]=fact(n[i])/(fact(r[i])*fact(n[i]-r[i])) ;
cout<<c[i];

return 0;

long long int fact(long long int num)
long long int k;
if(num==0)
num=1;
else

for(k=num-1;k>0;k--)
num=num*k;

return num;

【问题讨论】:

您需要任意长度的整数。该语言没有内置任何内容,因此您需要自己做(将大数存储在一个较小值的数组中并编写一个函数来相乘和打印它们)或使用像 GMP 这样的库 你可以通过召唤数学的古老力量来摆脱阶乘,避免溢出。 我应该使用 unsigned 吗? 没有标准类型适合 1000C500,无论是无符号还是有符号。 我不明白为什么这是重复的。如果您想扩大答案的范围,无论您如何简化表达式,都应该考虑使用像 boost 这样的多精度库。 【参考方案1】:

是时候接触一下数学了:

nCr = fact(n)/(fact(r)*fact(n-r))

一个例子让这更容易,让我们做 5C3:

5C3 = fact(5)/(fact(3)*fact(5-3))
    = fact(5)/(fact(3)*fact(2))
    = 5x4x3x2x1 / (3x2x1 * 2x1)
    = 5x4 / 2x1

所以我们可以看到一些因素会抵消;如果完整的fact(n) 溢出,这将非常有用。

定义一个范围阶乘:

rafa(a,b) = a*(a-1)*...*(b+1)*b where a > b
          = product(b..a)

然后

rafa(n,r) = fact(n)/fact(r)
-> nCr = rafa(n,r) / fact(r)

我们可以在这里停下来,我们会显着扩大 nr 的值集,我们可以计算它们的值而不会溢出。

加分

使用rafa(n,r)fact(r),我们可以看到当r 几乎与n 一样大时,问题的大部分规模将被取消。所以 100C97 = 100x99x98 / 3x2x1 = 100x33x49。

然后,考虑一个因子匹配算法(伪代码,就像 python):

numerElems = [100,99,98]
initialDenomElems = [3,2,1]

# cancelFactors modifies numerElems values, returns un-cancelled denominator elements
def cancelFactors(numerElems, denomElems):
    finalDenomElems = []
    for denom in denomElems:
        for factor in factorise(denom):
            for idx,numer in enumerate(numerElems):
                if isFactorOf(factor, numer):
                    numerElems[idx] = numer/factor
                else
                    finalDenomElems.push(factor)
    return finalDenomElems;

然后您可以执行分子元素的乘积除以其余分母元素的乘积的最终计算。因为我们知道 nCr 总是返回一个整数结果,所以我们知道当使用 cancelFactors 时它总是会取消所有的因子。因此,该算法最大化了不溢出的 n,r 对的可能空间。然而,正如写的那样,它是 O(n^3 * f),其中f 是获取整数的所有因子的成本,所以它不会很快。但是,对于较大的 n 和 r 值,它可能是在不使用不同类型的情况下计算结果的唯一方法。

【讨论】:

但是无论你在数学上多么狡猾,对于任何 C++ 类型来说,1000C500 仍然远远不够精确表示(根据我发现的一些随机在线计算器,2.7e299,它需要将近一千位)。您需要其他东西来支持整个范围 1 正是@MikeSeymour 先生,这才是真正的问题。 还有@spektre 先生,如果您无法回答问题,请不要将其标记为重复。我不是要求同一程序的更好方法,我可以优化它。【参考方案2】:

你有两个选择:

    使用多精度库,例如 Boost 提供的库:

http://www.boost.org/doc/libs/1_53_0/libs/multiprecision/doc/html/boost_multiprecision/tut/ints/egs/factorials.html

    尽可能简化表达式。只要您的值仍然很小,这将起作用。看看分子和分母?你能在那里简化一些事情吗?当您改变 N 和 R 时,值如何变化?在某些情况下,这些部分结果中的一个较小。尽量利用这一点。

【讨论】:

以上是关于c ++中较大值的数学计算[重复]的主要内容,如果未能解决你的问题,请参考以下文章

C如何计算sin()和其他数学函数?

C ++中没有2个操作数的数学计算器

[Shell]数学计算

Shell脚本笔记shell中的数学计算

c语言中的反函数怎么计算?

C语言问题 用一个栈来存符号把数学的中缀表达式计算出来