4 回答
TA贡献1884条经验 获得超4个赞
有是一种方法来确定操作是否可能溢出,使用操作数的最显著一个位和一点点基本的二进制数学知识的位置。
另外,任何两个操作数将导致(最多)比最大操作数的最高一位多一位。例如:
bool addition_is_safe(uint32_t a, uint32_t b) { size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b); return (a_bits<32 && b_bits<32);}
对于乘法,任何两个操作数将导致(最多)操作数的位总和。例如:
bool multiplication_is_safe(uint32_t a, uint32_t b) { size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b); return (a_bits+b_bits<=32);}
同样,您可以估算结果的最大大小a
,b
如下所示:
bool exponentiation_is_safe(uint32_t a, uint32_t b) { size_t a_bits=highestOneBitPosition(a); return (a_bits*b<=32);}
(当然,替换目标整数的位数。)
我不确定以最快的方式确定数字中最高的一位的位置,这是一种强力方法:
size_t highestOneBitPosition(uint32_t a) { size_t bits=0; while (a!=0) { ++bits; a>>=1; }; return bits;}
它并不完美,但是在你进行操作之前,这会让你知道任何两个数字是否会溢出。我不知道它是否比简单地以你建议的方式检查结果更快,因为highestOneBitPosition
函数中的循环,但它可能(特别是如果你事先知道操作数中有多少位)。
TA贡献1853条经验 获得超18个赞
Clang 3.4+和GCC 5+提供经过检查的算术内置函数。它们为这个问题提供了一个非常快速的解决方案,特别是与比特测试安全检查相比。
对于OP问题中的示例,它可以这样工作:
unsigned long b, c, c_test;if (__builtin_umull_overflow(b, c, &c_test)){ // returned non-zero: there has been an overflow}else{ // return zero: there hasn't been an overflow}
c_test
如果发生溢出,Clang文档没有指定是否包含溢出的结果,但GCC文档说它确实存在溢出。鉴于这两者似乎是__builtin
兼容的,可以安全地假设这也是Clang的工作方式。
__builtin
对于int大小,长大小和长long大小,每个算术运算都有一个可以溢出(加法,减法,乘法),带有符号和无符号变量。该名称的语法是__builtin_[us](operation)(l?l?)_overflow
:
u
对于未签名或s
对签名的 ;操作是其中之一
add
,sub
或mul
;没有
l
后缀意味着操作数是int
s; 一个l
手段long
; 两个l
意思是long long
。
因此,对于已检查的带符号长整数,它将是__builtin_saddl_overflow
。完整列表可以在Clang文档页面上找到。
GCC 5+和锵3.8+另外提供,如果没有指定值的类型工作的通用内建的:__builtin_add_overflow
,__builtin_sub_overflow
和__builtin_mul_overflow
。这些也适用于小于的类型int
。
内置程序降低到平台最佳状态。在x86上,它们检查进位,溢出和符号标志。
Visual Studio的cl.exe没有直接的等价物。对于无符号加法和减法,包括<intrin.h>
允许你使用addcarry_uNN
和subborrow_uNN
(其中NN是位数,如addcarry_u8
或subborrow_u64
)。他们的签名有点迟钝:
unsigned char _addcarry_u32(unsigned char c_in, unsigned int src1, unsigned int src2, unsigned int *sum); unsigned char _subborrow_u32(unsigned char b_in, unsigned int src1, unsigned int src2, unsigned int *diff);
c_in
/ b_in
是输入的进位/借位标志,返回值是输出的进位/借位。它似乎没有签名操作或乘法的等价物。
否则,Clang for Windows现在可以投入生产(对Chrome来说已经足够了),所以这也是一个选择。
TA贡献1796条经验 获得超4个赞
有些编译器可以访问CPU中的整数溢出标志,然后可以测试,但这不是标准的。
您还可以在执行乘法之前测试溢出的可能性:
if ( b > ULONG_MAX / a ) // a * b would overflow
- 4 回答
- 0 关注
- 1561 浏览
添加回答
举报