我希望有符号整数在它们变得太大时溢出。如果不使用下一个最大的数据类型(或者当我已经在 int128_t 时),我如何实现这一点?
例如,使用 8 位整数 19*12 通常是 260,但我想要1 11 10 01 00
截断第 9 位的结果,即 -27。
我希望有符号整数在它们变得太大时溢出。如果不使用下一个最大的数据类型(或者当我已经在 int128_t 时),我如何实现这一点?
例如,使用 8 位整数 19*12 通常是 260,但我想要1 11 10 01 00
截断第 9 位的结果,即 -27。
有符号溢出在 C 中是未定义的,这是真实的。
一种解决方案如下:
signed_result = (unsigned int)one_argument + (unsigned int)other_argument;
上述解决方案在从unsigned
到的最终转换中涉及实现定义的行为,int
但不调用未定义的行为。对于大多数编译平台的实现定义选择,结果正是您期望的二进制补码结果。
最后,针对众多平台之一的优化编译器,在这些平台上,实现定义的选择会强制编译器为您提供您期望的行为,并将上述代码编译为明显的汇编指令。
或者,如果您使用 gcc,那么选项-fwrapv
/-fno-strict-overflow
可能正是您想要的。它们为签名溢出环绕的标准提供了额外的保证。我不确定两者之间的区别。
只要您可以访问与您的unsigned
类型具有相同宽度的signed
类型(即多一个值位),就可以以正确的标准 C 方式执行此操作。演示int64_t
:
int64_t mult_wrap_2scomp(int64_t a, int64_t b)
{
uint64_t result = (uint64_t)a * (uint64_t)b;
if (result > INT64_MAX)
return (int64_t)(result - INT64_MAX - 1) - INT64_MAX - 1;
else
return (int64_t)result;
}
这不会产生任何有问题的中间结果。
根据 C 和 C++ 标准,有符号整数溢出是未定义的。如果不考虑特定平台,就无法完成您想要的。
您可以围绕 int 创建一个目标包装器,但这会涉及大量开销代码。
假设二进制补码有符号整数算术(如今这是一个合理的假设),对于加法和减法,只需转换为无符号数即可进行计算。对于乘法和除法,确保操作数为正数,强制转换为无符号,计算并调整符号。
听起来您想做无符号整数运算,然后将结果填充到有符号整数中:
unsigned char a = 19;
unsigned char b = 12;
signed char c = (signed char)(a*b);
应该给你你正在寻找的东西。如果没有,请告诉我们。
使用更大的数据类型。使用GMP,您将拥有您可能需要的所有空间。