C ++中的双精度(或pow(2,1000))

时间:2010-08-02 15:27:32

标签: c++ precision exponential

我正在使用Project Euler来提高我的C ++编码技能,为下一学期我们将要进行的编程挑战做准备(因为他们不让我们使用Python,嘘!)。

我正在#16,我正试图找到一种方法来保持2°°的真正精确度

例如:

int main(){
    double num = pow(2, 1000);
    printf("%.0f", num):
    return 0;
}

打印

  

10715086071862673209484250490600018105614050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

缺少大部分数字(来自python):

>>> 2**1000

  

10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376L

当然,我可以用Python 1线程编写程序

sum(int(_) for _ in str(2**1000))

立即给我结果,但我正试图找到一种方法在C ++中做到这一点。有什么指针吗? (哈哈...)

编辑:

标准库之外的东西对我来说毫无价值 - 在这些竞赛中只允许使用死树代码,而且我可能不会打印10,000行外部代码......

7 个答案:

答案 0 :(得分:7)

如果您只是跟踪char数组中的每个数字,这很容易。加倍数字是微不足道的,如果结果大于10,你只需减去10并将进位加到下一个数字。从值1开始,在倍增函数上循环1000次,然后就完成了。您可以使用ceil(1000*log(2)/log(10))预测所需的位数,或者只是动态添加它们。

剧透警报:看来我必须在任何人相信我之前显示代码。这是一个带有两个函数Double和Display的bignum的简单实现。为了简单起见,我没有把它变成一个类。数字以小端格式存储,首先是最低有效数字。




typedef std::vector<char> bignum;

void Double(bignum & num)
{
    int carry = 0;
    for (bignum::iterator p = num.begin();  p != num.end();  ++p)
    {
        *p *= 2;
        *p += carry;
        carry = (*p >= 10);
        *p -= carry * 10;
    }
    if (carry != 0)
        num.push_back(carry);
}

void Display(bignum & num)
{
    for (bignum::reverse_iterator p = num.rbegin();  p != num.rend();  ++p)
        std::cout << static_cast<int>(*p);
}

int main(int argc, char* argv[])
{
    bignum num;
    num.push_back(1);
    for (int i = 0;  i < 1000;  ++i)
        Double(num);
    Display(num);
    std::cout << std::endl;
    return 0;
}

答案 1 :(得分:3)

您需要一个bignum库,例如this one

答案 2 :(得分:3)

你可能需要一个指针(双关语)

在C ++中,你需要创建自己的bigint lib,以便像在python中一样。

答案 3 :(得分:2)

C / C ++对基本数据类型进行操作。您使用的double只有64位来存储1000位数。 double使用51位作为有效数字,使用11位作为幅度。

唯一的解决方案是使用像其他地方提到的bignum这样的库,或者推出自己的库。

答案 4 :(得分:2)

更新:我刚刚浏览了欧拉问题网站,发现问题13是关于大整数的求和。迭代方法在一段时间后会变得非常棘手,所以我建议使用问题#13中的代码来解决这个问题,因为2**N => 2**(N-1) + 2**(N-1)

使用bignums是作弊而不是解决方案。此外,您不需要计算2 ** 1000或类似的东西来获得结果。我会给你一个提示:

取2 ** N的前几个值:

0 1 2 4 8 16 32 64 128 256 ...

现在记下每个数字的数字总和:

1 2 4 8 7 5 10 11 13 ...

您应该注意到(x~=y表示x和y具有相同的数字总和)

1+1=2, 1+(1+2)=4, 1+(1+2+4)=8, 1+(1+2+4+8)=16~=7 1+(1+2+4+8+7)=23~=5

现在写一个循环。

Project Euler =在计算之前思考!

答案 5 :(得分:1)

如果你想在实际的基础上做这类事情,你正在寻找一个任意精度算术包。周围有一个数字,包括NTLlipGMPMIRACL

如果您只是为Project Euler做些事情,那么您可以编写自己的代码来提升能力。基本的想法是将你的大量存储在相当多的小块中,并在各块之间实现自己的携带,借用等。

答案 6 :(得分:0)

基本上不是pow(2, 1000)只有2次左移1000次吗?它应该在双浮点中具有精确的二进制表示。它不应该需要一个bignum库。