【问题标题】:C++ numbers add to a negativeC++ 数字加到负数
【发布时间】:2013-09-11 21:17:34
【问题描述】:

所以我只是在练习编写斐波那契数列的动态解决方案,它会返回第 n 个斐波那契数,但我一直遇到一个我无法弄清楚的问题。我得到两个正数加上一个负数!

代码:

int fib(int n) {
    vector<int> v;
    v.push_back(1);
    v.push_back(1);
    for (int i = 2; i <= n; i++) {
        v.push_back( v.at(i-1) + v.at(i-2) );
        cout << v.at(i-1) << " + " << v.at(i-2) << " = " << (v.at(i-1) + v.at(i-2)) << endl;
    }
    return v.at(n);
}

尝试运行 fib(50),注意 cout 仅用于调试

【问题讨论】:

  • 由于有符号整数溢出,您的行为未定义。
  • 他们只是不再教计算机如何工作,是吗?无需了解整数算术,有符号与无符号。只有高级语言,所以当一个 int 不够大时会让人感到惊讶。
  • 我两年前刚从大学毕业,我们甚至详细了解了 float 和 doubles 的工作原理,所以他们确实教过这类东西……但我猜有人没注意 :D
  • @CareyGregory,根据我的经验,不,他们没有。我在中学时将编程作为一种爱好,当我上高中时,我参加了两个可用的编程课程,但从未教过。我不能告诉你它是否在我的大学里教过,因为我测试了编程课程。不过肯定没有参加任何考试。

标签: c++


【解决方案1】:

您需要将int 更改为unsigned int 或更好的unsigned long long。您的结果超出了系统上int 的最大值。因为int 是有符号的,所以当most significant bit 被设置时,它变成一个负数。有关更多信息,请参阅标题为 maximum value of int 的 Stack Overflow 问题和 binary arithmatic 上的 Swarthmore College 页面。如果您使用的是 Visual Studio,请查看 MSDN 上的 Data Type Ranges 文章。

除了切换到unsigned long long 之外,您还应该检查诸如此类的溢出错误并抛出异常。您的代码的修订版本可能如下所示。

unsigned long long fib(int n) {
    vector<unsigned long long> v;
    v.push_back(1);
    v.push_back(1);
    for (int i = 2; i <= n; i++) {
        if( v.at(i-1) > (std::numeric_limits<unsigned long long>::max() - v.at(i-2)) )
            throw std::overflow_error("number too large to calculate");
        v.push_back( v.at(i-1) + v.at(i-2) );
        cout << v.at(i-1) << " + " << v.at(i-2) << " = " << (v.at(i-1) + v.at(i-2)) << endl;
    }
    return v.at(n);
}

您还需要确保调用您的函数的代码可以使用try... catch... 处理异常。这是一个例子

try {
    std::cout << "2000th number = " << fib(2000) << std::endl;
} catch( std::overflow_error& ex ) {
    std::cerr << ex.what() << std::endl; 
}

【讨论】:

  • "你需要把int改成unsigned int或者更好的unsigned long。"取决于他使用的编译器。我相信 MSVC 中的 long 只是 4 个字节(不是 8 个)。要真正保证整数的宽度,请使用stdint.h(或cstdint)头文件。
  • 在许多平台上,int 和 long 大小相同,无论是否有符号。
  • @inspector-g 和@Carey Gregory,你说得对,我实际上是想输入unsigned long long。我确定了答案。我将其归咎于观看小布里斯科县时分心。
  • 好的,但是做long long只会推迟问题。一个非常好的答案将解决如何避免(或处理)整数溢出,而不管类型的大小。将其添加到您的答案中,我会 +1。
  • @CareyGregory,我添加了溢出检查,并抛出了 overflow_error 异常。
【解决方案2】:

由于 C 如何将您的 int (signed int) 存储在内存中,因此最高有效位表示负数。所以如果你用大数溢出它,你会得到负数。

参考:

【讨论】:

  • 哪位是“第一个”位?那是 C++ 标准吗?
  • 这可能是错误的 - 请参阅此问题的最佳答案 stackoverflow.com/questions/12125650/…[ 示例:本国际标准允许整数类型的 2 的补码、1 的补码和带符号的幅度表示。 —结束示例] [§3.9.1/7]
猜你喜欢
  • 1970-01-01
  • 2022-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-10
相关资源
最近更新 更多