C++ 大数溢出检测(unsigned long long)
C++ overflow detection for large numbers (unsigned long long)
我正在处理大整数 (unsigned long long) 并且需要防止溢出情况。无论是否确实存在,代码都会抛出异常:
try
{
unsigned long long y = std::numeric_limits<unsigned long long>::max() - 2;
unsigned long long z = 1;
int size = - 1;
if((y+z) ^ y < 0) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
throw std::overflow_error("overflow of y+z");
//int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
printf("%d\n", y*(y+z));
}
catch(exception& e)
{
cout << e.what() << endl;
}
由于它已经是最大的数据类型(64 位),因此没有提升到更大的空间。
新代码:
try
{
unsigned long long int y = std::numeric_limits<unsigned long long int>::max() - 2;
unsigned long long int z = std::numeric_limits<unsigned long long int>::max() / 2;
unsigned long long delta = std::numeric_limits<unsigned long long int>::max() - y;
int size = - 1;
if(z > delta) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
throw std::overflow_error("overflow of y+z");
//int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
printf("%d\n", (y+z));
}
catch(exception& e)
{
cout << e.what() << endl;
}
y < 0
将永远为假,任何 xor 0 将永远是那个东西(你是否错过了 <
的评估优先级高于 ^
?)。
因此,除非 x + y
mod <the max value>
恰好等于 0,否则您将抛出(并且可能在实践中似乎总是抛出,除非您设计了特定的输入)。
也许你的意思是这样的:if((std::numeric_limits<unsigned long long>::max() - y) < z) throw ...;
你有两个问题。主要是operator precedence:<
高于^
。这是在启用所有警告的情况下进行编译的一个重要原因,因为 gcc 和 clang 都会给我关于此表达式的警告并建议使用括号!
编译器评估的表达式实际上是:
if ( (y+z) ^ (y < 0) )
因为 y < 0
的计算结果为 0
,所以就是:
if (y+z)
这显然是 true
。但即使你的括号是正确的,如:
if (((y+z) ^ y) < 0) { ... }
那个表达很平凡false
。它仍然具有类型 unsigned long long
,永远不会评估为 < 0
。
我正在处理大整数 (unsigned long long) 并且需要防止溢出情况。无论是否确实存在,代码都会抛出异常:
try
{
unsigned long long y = std::numeric_limits<unsigned long long>::max() - 2;
unsigned long long z = 1;
int size = - 1;
if((y+z) ^ y < 0) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
throw std::overflow_error("overflow of y+z");
//int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
printf("%d\n", y*(y+z));
}
catch(exception& e)
{
cout << e.what() << endl;
}
由于它已经是最大的数据类型(64 位),因此没有提升到更大的空间。
新代码:
try
{
unsigned long long int y = std::numeric_limits<unsigned long long int>::max() - 2;
unsigned long long int z = std::numeric_limits<unsigned long long int>::max() / 2;
unsigned long long delta = std::numeric_limits<unsigned long long int>::max() - y;
int size = - 1;
if(z > delta) //If y+z causes overflow its sign will be changed => y and (y+z) will have opposite signs
throw std::overflow_error("overflow of y+z");
//int* myarray= new int[size]; VS Debug Library catches it earlier than catch()
printf("%d\n", (y+z));
}
catch(exception& e)
{
cout << e.what() << endl;
}
y < 0
将永远为假,任何 xor 0 将永远是那个东西(你是否错过了 <
的评估优先级高于 ^
?)。
因此,除非 x + y
mod <the max value>
恰好等于 0,否则您将抛出(并且可能在实践中似乎总是抛出,除非您设计了特定的输入)。
也许你的意思是这样的:if((std::numeric_limits<unsigned long long>::max() - y) < z) throw ...;
你有两个问题。主要是operator precedence:<
高于^
。这是在启用所有警告的情况下进行编译的一个重要原因,因为 gcc 和 clang 都会给我关于此表达式的警告并建议使用括号!
编译器评估的表达式实际上是:
if ( (y+z) ^ (y < 0) )
因为 y < 0
的计算结果为 0
,所以就是:
if (y+z)
这显然是 true
。但即使你的括号是正确的,如:
if (((y+z) ^ y) < 0) { ... }
那个表达很平凡false
。它仍然具有类型 unsigned long long
,永远不会评估为 < 0
。