我希望签名整数在它们变得太大时溢出。如何在不使用下一个最大数据类型的情况下(或者当我已经在int128_t时)实现这一目标?
例如,使用8位整数19 * 12通常为260,但我希望结果1 11 10 01 00
与第9位截止,因此-27。
在C和that's for real中未定义有符号溢出。
一个解决方案如下
signed_result = (unsigned int)one_argument + (unsigned int)other_argument;
上述解决方案涉及从unsigned
到int
的最终转换中的实现定义行为,但不调用未定义的行为。对于大多数编译平台的实现定义选择,结果正是您期望的两个补码结果。
最后,an optimizing compiler for one of the numerous platforms on which implementation-defined choices force the compiler to give you the behavior you expect将上面的代码编译成明显的汇编指令。
或者,如果您使用的是gcc,那么选项-fwrapv
/ -fno-strict-overflow
可能就是您想要的。它们提供了有关签名溢出的标准的额外保证。我不确定两者之间的区别。
根据C和C ++标准,未定义有符号整数溢出。没有特定的平台,没有办法实现你想要的。
您可以在int周围创建一个目标包装器,但这将涉及相当多的开销代码。
听起来你想做无符号整数运算,然后将结果填充到有符号整数:
unsigned char a = 19;
unsigned char b = 12;
signed char c = (signed char)(a*b);
应该给你你想要的东西。如果没有,请告诉我们。
假设二进制补码有符号整数运算(这些天是合理的假设),对于加法和减法,只需转换为无符号进行计算。对于乘法和除法,确保操作数为正,转换为无符号,计算和调整符号。
只要您可以访问与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;
}
这不会产生任何有问题的中间结果。
使用更大的数据类型。使用GMP,您将拥有您可能需要的所有空间。