我正在使用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行外部代码......
答案 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)
如果你想在实际的基础上做这类事情,你正在寻找一个任意精度算术包。周围有一个数字,包括NTL,lip,GMP和MIRACL。
如果您只是为Project Euler做些事情,那么您可以编写自己的代码来提升能力。基本的想法是将你的大量存储在相当多的小块中,并在各块之间实现自己的携带,借用等。
答案 6 :(得分:0)
基本上不是pow(2, 1000)
只有2次左移1000次吗?它应该在双浮点中具有精确的二进制表示。它不应该需要一个bignum库。