【问题标题】:`unsigned long long` too small to represent number?`unsigned long long` 太小而不能代表数字?
【发布时间】:2015-06-21 02:43:39
【问题描述】:

我一直在尝试为 Project Euler 找到问题 3 的答案,我需要在其中找到最大的质因数 600851475143,但我的程序挂断了这个数字,而不是更小的数字(或有时更大的数字)。我删除了程序寻找素数分解的更通用目的,希望它可以减少计算时间并可能给我一个答案,但它没有。以前,当程序从 1 而不是输入开始时,它给了我最低的质数,17,但仅此而已。现在它什么也没给我。

对于其他人来说,似乎可行的是增加数据类型的大小并将“ULL”附加到变量的末尾。这对我不起作用。其他人建议创建一个大数字类,但我还没有足够的知识来做到这一点,或者根本无法使用类,真的。这是程序。

#include <iostream>
using namespace std;

bool is_prime(unsigned long long int input);
void factor_number(unsigned long long int input);

int main()
{
    unsigned long long int input = 600851475143ULL;

    cout << "Hello World!\n\n";

    if (is_prime(input) == false)
        factor_number(input);
    else
        cout << input << 1;

    cin.get();

    return 0;
}

bool is_prime(unsigned long long int input)
{
    for (int i = 1; i <= input; i++)
    {
        if (i != 1 && i != input)
        {
            if (input % i == 0)
            {
                return false;
            }
        }
        else if (i == input)
            return true;
    }
}

void factor_number(unsigned long long int input)
{
    unsigned long long int i = input;

    while (input % i != 0 || is_prime(i) == false)
    {
        i--;
    }
    cout << i << endl;
}

【问题讨论】:

  • 在我的实现(x86_64 的 GCC)unsigned long long 可以容纳高达 18446744073709551615 的值,因此 600851475143 应该很适合。您可以通过std::numeric_limits了解您的实施限制。
  • 比较 intunsigned long long 可能是个坏主意。由于该程序正在探索数据类型容量的上限,因此这是一个非常糟糕的主意。您可以在 int 中填充的正数本质上小于 unsigned int,而且很可能远远小于 unsigned long long。通过使所有类型都匹配,您不会损失太多。

标签: c++


【解决方案1】:
bool is_prime(unsigned long long int input)
{
    for (int i = 1; i <= input; i++)

unsigned long long int input 可以存储一个值 [0,2^64)。

int i 可以存储 [-(2^31),2^31) 之间的值。

i2,147,483,647 并且您将其递增时,它变为负数,因此当input >= 2^31 时,循环条件i &lt;= input 永远不会为假。如果 iunsigned int,则值 >= 2^32 时会出现问题。

#include <iostream>
#include <cstdint>
#include <limits>

int main() {
    int i = std::numeric_limits<int>::max();
    std::cout << i << "\n";
    ++i;
    std::cout << i << "\n";
}

现场演示:http://ideone.com/kmeXti

当您比较 iinput 时,您的编译器可能会向您发出警告,但您选择忽略它。

你可以这样修复你的代码:

#include <cstdint>

bool is_prime(uint64_t input)
{
    for (uint64t_t i = 1; i <= input; ++i) {

--- 编辑 ---

您的主要功能也这样做:

for (int i = 1; i <= input; i++)
{
    if (i != 1 && i != input)
    {

循环内的测试条件可能会很昂贵(在这种情况下,您需要对循环的每次迭代都进行测试)。如果您担心代码的性能,首先应该尝试消除这些测试。

循环包含对i != input 的测试 - 所以让我们将其提升到循环条件中:

for (uint64_t i = 1; i < input; i++)
{
    ...
}
return true;

现在我们不需要在循环内测试i != input,但我们仍然需要测试那个讨厌的 1。我们可以在开始时添加一些显式测试:

if (input < 4) {
    return (input > 1); // 2 and 3 are prime, 0 and 1 are not
}

但更重要的是,我们可以快速消除所有偶数。如果数字的最低位是'0',那么这个数字是偶数:

if ((input & 1) == 0) // even number
    return false;

但现在我们知道这个数字不可能是偶数,我们也可以少做除法测试。把它们放在一起:

#include <iostream>

bool is_prime(uint64_t input)
{
    if (input < 4)
    {
        // eliminate 1, 2 and 3.
        return (input > 1);
    }
    // Eliminate even numbers
    if ((input & 1) == 0)
        return false;
    // we've eliminated even numbers, so the smallest
    // possible divisor is 3, start from there, but
    // we can also skip all even divisors!
    for (uint64_t div = 3; div <= input / 3; div += 2)
    {
        if ((input % div) == 0)
            return false;
    }
    return true;
}

int main()
{
    for (uint64_t i = 0; i < 64; ++i)
    {
        std::cout << i << ": " << (is_prime(i) ? "yes" : "no") << '\n';
    }
}

http://ideone.com/aJqApL

【讨论】:

  • Bryan 可以通过这种方式解决特定问题,但他的方法存在的问题远不止于此......
  • 同意,当他显然只是在做早期实验时,我不确定是否要启动“这是修复素数的方法”实施。
  • 查看 --EDIT-- 以获得更彻底的 is_prime 解决方案
猜你喜欢
  • 2016-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 2023-03-22
  • 2016-12-20
相关资源
最近更新 更多