`unsigned long long`太小而无法代表数字?

时间:2015-06-21 02:43:40

标签: c++

我一直试图得到问题3的项目Euler的答案,我需要找到最大的素数因子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;
}

1 个答案:

答案 0 :(得分:6)

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并且您将其递增时,它会变为负值,因此当i <= input为&gt; = 2 ^时,循环条件input永远不会为假31。如果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
}

但更重要的是,我们可以快速消除所有偶数。如果数字的最低位是&#39; 0&#39;然后数字是均匀的:

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