我在Project Euler中遇到了一个奇怪的问题,与10号问题有关。任务是计算小于两百万的所有质数之和。
我使用了int类型的变量作为求和结果,我的算法得出了答案,但当我将它粘贴验证答案时,发现它是错误的。
后来发现,结果太大无法容纳在int类型中,但这难道不应该导致溢出错误之类的吗?相反,它只返回了一个远离实际答案的值。
当我将类型更改为long后,一切都很好。
我在Project Euler中遇到了一个奇怪的问题,与10号问题有关。任务是计算小于两百万的所有质数之和。
我使用了int类型的变量作为求和结果,我的算法得出了答案,但当我将它粘贴验证答案时,发现它是错误的。
后来发现,结果太大无法容纳在int类型中,但这难道不应该导致溢出错误之类的吗?相反,它只返回了一个远离实际答案的值。
当我将类型更改为long后,一切都很好。
默认情况下,C#整数运算不会在溢出时抛出异常。您可以通过项目设置或通过进行 checked
计算来实现此目的:
int result = checked(largeInt + otherLargeInt);
现在这个操作会抛出异常。
相反的是unchecked
,它使得任何操作都被显式地视为未经检查的。很明显,这只有在项目设置中启用了检查操作时才有意义。
checked
块或表达式中,会抛出一个OverflowException
。如果您不关心溢出,请不要检查它们。您的校验和示例将是一个典型的用例,您不想检查溢出。这通常会循环(而不是归零)。但是,请注意,C#(和其他语言)默认情况下会执行一些称为“整数提升”的聪明操作。添加两个字节的结果是一个整数。如果直接打印它,结果可能比byte
可以容纳的要大。您需要重新分配它到一个byte
(或进行强制转换)以截断它。 - Konrad Rudolph在 C# 中,OverflowException
不会被抛出(在 VB 中默认会抛出该异常)。
若要抛出该异常,您需要将代码嵌入到 checked
上下文中:
byte value = 241;
checked
{
try
{
sbyte newValue = (sbyte) value;
Console.WriteLine("Converted the {0} value {1} to the {2} value {3}.",
value.GetType().Name, value,
newValue.GetType().Name, newValue);
}
catch (OverflowException)
{
Console.WriteLine("Exception: {0} > {1}.", value, SByte.MaxValue);
}
}
MSDN有更详细的解释:
对于算术、类型转换等操作如果要抛出OverflowException,必须发生在已启用检查的上下文中。默认情况下,Visual Basic中的算术运算和溢出是已启用检查的;而在C#中则没有。如果该操作发生在未启用检查的上下文中,则结果通过丢弃任何无法适应目标类型的高位比特来进行截断。
这是因为默认情况下,C#不会对整数溢出和下溢抛出任何异常。您可以在此处执行几个操作。
选项1
您需要启用异常才能被抛出,方法是进入项目 => 属性 => 生成选项卡 => 高级 => 检查算术溢出下溢(确保您选中该选项)。
请确保您选中该选项
选项2
使用“checked”块并抛出溢出异常以处理情况。一个代码示例片段如下:
try
{
checked
{
int y = 1000000000;
short x = (short)y;
}
}
catch (OverflowException ex)
{
MessageBox.Show("Overflow");
}
catch (Exception ex)
{
MessageBox.Show("Error");
}
我已经添加了一条评论,但是对于您中的一些人可能会感兴趣:
msdn 告诉我们:
整数算术溢出会抛出OverflowException或舍弃结果的最高有效位
但是
十进制算术溢出总是抛出OverflowException。
另外
当整数溢出发生时,会发生什么取决于执行上下文,可以检查或未检查。在检查上下文中,将抛出OverflowException。在未检查的上下文中,结果的最高有效位将被舍弃,执行将继续。因此,C#为您提供了处理或忽略溢出的选择。
默认情况下,C# 不会检查整数的算术溢出。您可以使用 /checked
编译器选项 或在 Visual Studio 中启用“检查算术溢出/下溢”(项目属性-生成-高级)来更改此设置。
您可以使用checked
和 unchecked
关键字 以按需覆盖默认设置。如果您依赖于代码中的检查操作,则明确使用 checked
启用检查是个好主意。
int j = checked(i * 2);
checked
{
int j = i * 2;
// Do more stuff
}
OverflowException
异常,而十进制运算始终会抛出 OverflowException
异常。另请参见 C# 运算符。您可以通过添加以下内容,在csproj
中直接设置checked
:
<PropertyGroup>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
这相当于在设计师中勾选 检查算术溢出/下溢
复选框。