【问题标题】:Project Euler #16: Answer 2 digits off欧拉计划 #16:回答 2 位数
【发布时间】:2015-05-26 19:15:16
【问题描述】:

我得到的答案是 1364,但正确的答案是 1366。 我得到错误答案是因为我将double digits = pow(2,1000) 转换为string dig = std::to_string(digits),还是我还缺少其他东西?

#include <iostream>
using std::endl; using std::cout;
#include <string>
using std::string;
#include <cmath>

int computeSum(string);

int main(void){

    double digits = pow(2,1000);

    string dig = std::to_string(digits);

    cout << computeSum(dig) << endl;

    return 0;

}

int computeSum(string dig){

    int sum(0);

    for(char n : dig)
        sum+=(n-48); // or (n-'0')  

    return sum;

}

编辑:

解决方案: 我需要添加if (n!='.') 条件,因为(n-48). 转换为其ASCII 值46,给我一个-2。

for(char n : dig){
    if(n!='.')
        sum+=(n-48); // or (n-'0')  
}

【问题讨论】:

  • 我在 PHP 中使用了 BC 数学 来解决这个问题。在谷歌搜索 C++ 替代品后,我发现 the following repository.
  • 这就是为什么其中一些问题存在偏见,具体取决于所使用的语言。这对于使用 JavaBigInteger 类来说是微不足道的。 C++ 没有这样的内置功能,除非你使用第三方库。
  • 我发现了问题。当您计算 2 ^ 1000 并将其存储在 digits 中时。结果将有一个点(很明显!)。当您将其转换为字符串时,它仍将包含此点。现在一个点是 46,删除 48 你得到 -2。所以当你遍历你的字符串时,它会偶然发现点并添加-2。有你的2位数的问题。您可以在 for 循环中添加 if 语句,以在遇到点字符时返回总和。
  • HamZa,你这个天才。那行得通。我添加了一个if (n!='.'),现在答案是正确的。
  • @ishyfishy 我现在开始想知道你得到的是可移植的还是实现定义的。这似乎非常可疑,我不会打赌。在这种情况下可能没问题,因为您使用的是 2 的幂。

标签: c++


【解决方案1】:

你的答案被取消了,因为在这条线上

double digits = pow(2, 1000); 

您将结果存储为double,但是double 在表示这么大的整数时会丢失精度,因为它使用floating point representation

您应该使用整数,并且可能在乘法循环中迭代地计算数字的总和,在每次迭代时减少结果。否则,你需要使用一个大的 int 库,比如Boost.Multiprecision。后者的快速示例:

#include <boost/multiprecision/cpp_int.hpp>
#include <iostream>

int main()
{
    using namespace boost::multiprecision;

    // Repeat at arbitrary precision:
    cpp_int u = 2;
    cpp_int result = pow(u, 1000);

    int sum = 0;
    for (auto elem : result.str()) // use the string representation
        sum += elem-'0';

    std::cout << result.str() << std::endl; // prints 2^1000
    std::cout << sum << std::endl; // prints the sum of the digits
}

编辑

我意识到在这种情况下@HamZa 在您的答案下方的评论是正确的。 double 范围内的 2 的幂由浮点表示忠实地表示,因此在这种情况下不会丢失任何精度。问题确实是出现在字符串表示中的.0000。但是,如果你使用3作为基础,那么所有的赌注都没有,你不能简单地使用std::pow

【讨论】:

  • 请参阅:stackoverflow.com/a/7372091/4907651。这个答案不正确吗?
  • @ishyfishy 抱歉,我刚刚编辑了它。我首先以为您使用int。另请参阅您刚刚链接的答案的最后一部分。
  • 双重损失精度是我想到的最后一件事,因为答案只有 2 位数。谢谢,我会尝试你建议的方法,看看是否有效。
【解决方案2】:

你也可以使用这种转换方式

#include <iostream>
# include <cmath>
# include <string>
using namespace std;

int main() {
    cout<<std::to_string(pow((double)2,1000));
    return 0;
}

http://ideone.com/MZp1tN

【讨论】:

  • 这真的很奇怪。如果我在 Ideone 上使用该程序的输出初始化我的字符串,答案是 1366。但如果我让我的字符串等于 std::to_string(pow((double)2,1000)),我得到 1364。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多