C#の浮動小数点のオーバーフロー判定に注意:checked抜ける
Untiy を使った開発を C# で行っていたのですが、オーバーフローのチェックで躓きました。 C# では、浮動小数点のオーバーフローの扱いに注意する必要があるようです。
一般に、コンパイラオプションないし checked, unchecked 構文によってオーバーフローの検出は可能ですが、 浮動小数点の場合には、checked によるオーバーフローの検出は有効ではありませんでした。 (なお他の方法については検証していません。)
検証コード
以下のコードのように int と float で意図的にオーバーフローを起こして検証しました。 (double についても float と同じ結果が得られていますが割愛)
- 検証環境
- Windows10 Pro 64bit
- VisualStudio Professional 2015
- .NET Framework 4.6.x
int intValue = int.MaxValue;
float floatValue = float.MaxValue;
#region int
try
{
checked
{
intValue += 1;
}
}
catch (System.OverflowException e)
{
Console.WriteLine("int Exception(A) : " + e);
}
catch (System.Exception e)
{
Console.WriteLine("int Exception(B) : " + e);
}
Console.WriteLine("int MaxValue : " + int.MaxValue);
Console.WriteLine("int currentValue : " + intValue);
#endregion
#region float
try
{
checked
{
floatValue += 1;
}
}
catch (System.OverflowException e)
{
Console.WriteLine("float exception(A) : " + e);
}
catch (System.Exception e)
{
Console.WriteLine("float exception(B) : " + e);
}
Console.WriteLine("float MaxValue : " + float.MaxValue);
Console.WriteLine("float CurrentValue : " + floatValue);
if (float.IsInfinity(floatValue))
{
Console.WriteLine("floatValue is Infinity");
}
if (float.IsNaN(floatValue))
{
Console.WriteLine("floatValue is NaN");
}
if (floatValue == float.MaxValue)
{
Console.WriteLine("floatValue is MaxValue");
}
else
{
Console.WriteLine("Any");
}
#endregion
結果
結果は次のようになりました。int のオーバーフローは検出されますが、float のオーバーフローは検出されません。 また float 型の値は、NaN でも Infinity でもなく MaxValue を維持していました。
int Exception(A) : System.OverflowException: 算術演算の結果オーバーフローが発生しました… int MaxValue : 2147483647 int currentValue : 2147483647 float MaxValue : 3.402823E+38 float CurrentValue : 3.402823E+38 floatValue is MaxValue
なお Unity では Mono (実験時 3.x) を使っていますが、同様の現象が確認できています。 先と重なりますが double でも同じ現象が確認できています。
少なくとも checked 構文を使って浮動小数点のオーバーフローを検出できないことは覚えておいたほうがよさそうです。 今後のバージョンアップでは対応される可能性はありますけども。