首页 > 解决方案 > c++ 的除法的其余部分得到“堆栈溢出”异常

问题描述

我试图理解 C++ 中的一些概念,我制作了这段代码来获取除法的其余部分(如 % 运算符):

double resto(double a, double b) {
    if (a == b) return 0;
    else if (a < b) return a;
    else {
        return resto(a-b, b);
    }
}

当我使用 (12,3) 或 (2,3) 等较低的数字运行它时,它运行良好。但是,如果我尝试使用参数 (2147483647 * 1024, 3) 运行它,我会得到:

Stack overflow (parameters: 0x0000000000000001, 0x000000F404403F20)

由于我是 C++ 新手,我不确定它是 Visual Studio 2017 的问题还是编译器或堆栈内存等。

标签: c++visual-studio-2017stack-overflow

解决方案


resto(2147483647 * 1024, 3); 

将递归 2147483647 * 1024 / 3,或约 7330 亿次。每个递归调用都使用少量的自动存储来存储参数和簿记,并且程序可能会在达到一百万次迭代之前耗尽存储空间。

为此,您将不得不使用循环或更智能的逻辑(例如,减去较大的倍数,b直到使用较小的数字开始有意义),但fmod可能会更快,更有效。

其他注意事项:

2147483647 * 1024

是一个整数乘以一个整数。如果您的系统是 16 位或 32 位,则此数学运算将在ints 中发生并溢出。int当您溢出有符号整数时发生的确切情况是undefined,但通常该数字会进行2s补码环绕(假设 32 位整数为 -1024)。更多关于溢出整数的细节在 C++ 中是否有符号整数溢出仍然是未定义的行为?. 采用

2147483647.0 * 1024

强制浮点数。

还要注意浮点数学是否损坏?浮点数是不精确的,通常很难得到应该与实际相同的浮点数。a == b当您期望为真时,通常是假的。此外,如果一个数字变得比另一个大太多,则a-b可能没有明显的效果,因为b在结尾的噪音中丢失了a。两者之间的差异无法正确表示。


推荐阅读