C 编程中算术下溢和上溢是什么意思?
4 回答
溢出
来自http://en.wikipedia.org/wiki/Arithmetic_overflow:
当计算产生的结果在幅度上大于给定寄存器或存储位置可以存储或表示的结果时发生的情况。
因此,例如:
uint32_t x = 1UL << 31;
x *= 2; // Overflow!
请注意,正如@R 在下面的评论中提到的,C 标准建议:
涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果会以比结果类型可以表示的最大值大一的数字为模减少。
当然,这是“溢出”的一个相当特殊的定义。大多数人会将模减少(即环绕)称为“溢出”。
下溢
来自http://en.wikipedia.org/wiki/Arithmetic_underflow:
当浮点运算的真实结果在幅度上小于目标数据类型中可表示为正常浮点数的最小值时(即,接近于零),计算机程序中可能发生的情况。
因此,例如:
float x = 1e-30;
x /= 1e20; // Underflow!
计算机只使用 0 和 1 来表示数据,因此可以表示的值的范围是有限的。很多计算机使用32位来存储整数,所以这种情况下可以存储的最大无符号整数是2^32 -1 = 4294967295。但是第一位是用来表示符号的,所以,其实最大值是2^31 - 1 = 2147483647。
超出允许范围的整数需要比可以存储更多的位的情况称为溢出。
同样,对于实数,太小而无法存储的指数会导致下溢。
int 是 C 中最常见的数据类型,是 32 位数据类型。这意味着每个 int 在内存中都有 32 位。如果我有变量
int a = 2;
这实际上将在内存中表示为 32 位二进制数:00000000000000000000000000000010。
如果您有两个二进制数,例如
100000000000000000000000000000000
和
10000000000000000000000000000000,
它们的总和为 1000000000000000000000000000000000,即 33 位长。但是,计算机只取 32 个最低有效位,它们全为 0。在这种情况下,计算机识别出总和大于 32 位中可以存储的值,并给出溢出错误。
下溢基本上是在相反方向发生的相同事情。C 使用的浮点标准允许小数点后 23 位;如果数字的精度超过这一点,它将无法存储这些位。这会导致下溢错误和/或精度损失。
下溢完全取决于给定的算法和给定的输入数据,因此程序员没有直接控制。另一方面,上溢取决于程序员为每个堆栈保留的内存空间量的任意选择,以及此选择确实会影响可能发生溢出的次数