こんにちは!
今日は「VB.NET で 10 / 0
を実行すると DivideByZeroException ではなく Infinity になるのはなぜ?」という、ちょっとモヤッとする現象をテーマにお話ししたいと思います。途中で C# との違いにも触れますので、両言語を行き来するエンジニアさんはぜひ最後までお付き合いください。
0. 動作確認環境
下記の環境で動作確認しました。
- .NET9
- Visual Studio 2022
1. そもそも何が起きているの?
まずは実験結果を表にまとめます。
式 | 評価される型 | 0 で割った時の挙動 |
---|---|---|
a / b | Double | IEEE 754 に従い Infinity / -Infinity / NaN |
a \ b | Integer | DivideByZeroException をスロー |
a / b (Decimal) | Decimal | DivideByZeroException をスロー |
ポイント
/
演算子は「浮動小数点除算」。両オペランドが整数でも内部でDouble
に暗黙拡張します。\
演算子は「整数除算」。結果も整数。Decimal
型だけは“金融向け”の特別扱いで、ゼロ除算時は例外になります。
2. VB.NET の「/」は何でもかんでも Double にする
VB の /
は、歴史的経緯から「浮動小数点で割り算しますよ」というおせっかい仕様になっています。たとえば:
Dim x As Integer = 10 Dim y As Integer = 0 Dim z = x / y ' z の型は Double Console.WriteLine(z) ' => ∞
両方 Integer
なのに、暗黙的に Double
へ拡張されたうえで計算されるのがミソです。Double
は IEEE 754 標準の「±Infinity と NaN を返せばいいよ」というルールに従っているため、例外は飛びません。
*「0 で割ったらクラッシュする」*という固定観念があるとびっくりしますが、仕様なので仕方ありません。
3. ゼロ除算で例外を投げたいなら「\」を使う
整数計算が目的で DivideByZeroException を必ずキャッチしたい場面もあります。そんなときは /
ではなく \
を選びます。
Dim answer = 10 \ 0 ' DivideByZeroException
Option Strict
を付けても挙動は変わらないので、演算子選択こそが分かれ道です。
小ネタ:
Decimal
はケタ数重視なので例外派
Decimal
型は為替計算などで誤差を嫌うため、「Infinity でお茶を濁すくらいなら即例外!」というポリシーです。VB でも C# でも同じく例外になります。
4. C# と比べるとどう違うの?
C# の /
は「オペランドの型に合わせて振る舞いを変える」賢い子です。主要パターンは次の 3 つ。
C# の式 | 型決定 | 0 で割った時 |
---|---|---|
10 / 0 | int ÷ int なので整数除算 | DivideByZeroException |
10.0 / 0 | double | Infinity |
10m / 0m | decimal | DivideByZeroException |
つまり C# では 整数÷整数なら整数計算、少しでも浮動小数点が混ざれば浮動小数点計算、というシンプルなルールです。VB のような「とりあえず Double にするよ!」という強制拡張はありません。
また、C# には整数除算用の \
演算子は存在しません。整数÷整数でも /
を使い、結果が整数で返ってくるだけです(余りは切り捨て)。
ポイントを一言で
- VB: 演算子で意味が変わる (
/
は Double,\
は Integer)。- C#: 変数の型で意味が変わる。演算子は
/
ひとつ。
5. ありがちな落とし穴と対策
5-1. Infinity を見落として計算を続行する
浮動小数点計算では例外が出ないので、PositiveInfinity
がそのまま次の計算へ流れていきます。最終的にログを見て「NaN だらけ!」と頭を抱えるパターンが多いです。
対策:
- 途中結果を
Double.IsInfinity
/Double.IsNaN
でチェック - 可能なら
\
(整数除算)かDecimal
を使う Option Strict On
+ こまめな明示的キャストで意図しない型拡張を防ぐ
5-2. C# ↔ VB 移植時の落とし穴
C# の /
を VB にコピペすると、整数演算なのに例外が出なくなる場合があります。レビュー時に「VB の /
は浮動小数点だよ」と 3 回くらい念押しすると事故を防げます。
6. 具体的なサンプルで感覚をつかもう
VB.NET
' 浮動小数点除算 Dim r1 As Double = 10 / 0 ' Infinity ' 整数除算 Try Dim r2 As Integer = 10 \ 0 ' 例外 Catch ex As DivideByZeroException Console.WriteLine("割り算できませんでした") End Try ' Decimal Try Dim r3 As Decimal = 10D / 0D ' 例外 Catch ex As DivideByZeroException Console.WriteLine("Decimal も例外です") End Try
C#
// 整数÷整数 int a = 10 / 0; // DivideByZeroException // 浮動小数点 double b = 10.0 / 0; // Infinity // Decimal decimal c = 10m / 0m; // DivideByZeroException
見比べると、VB は演算子で決まる、C# はオペランドの型で決まるという対比がはっきりしますね。
7. 「とはいえ」浮動小数点で Infinity を返すメリットもある
- 高速演算:例外処理よりずっと速い
- GPU・SIMD 親和性:数値計算ライブラリでは常識
- エラー伝搬:途中で止めずに「変な値」を最後に一括確認できる
科学技術計算や機械学習分野ではInfinity/NaN 文化が根付いているので、「ゼロで割っても走り続ける」特性は案外便利だったりします。
8. まとめ
- VB.NET の
/
は“浮動小数点除算専用で、整数オペランドでも暗黙に Double 化 → ゼロ除算は例外ではなく Infinity/NaN。 - 整数除算して例外を取りたいときは
\
を使う。 Decimal
型は VB でも C# でもゼロ除算で 必ずDivideByZeroException
。- C# は演算子が
/
ひとつだけ。整数同士なら例外、浮動小数点を含めば Infinity/NaN、Decimal なら例外。 - 移植やレビュー時は「VB の
/
= C# のdouble
除算」と意識しておくと安全。
というわけで、10 / 0 が Infinity になる理由は「演算子の暗黙拡張」と「IEEE 754 のお約束」でした。ゼロ除算の扱いは言語仕様でこうも変わるんだなぁ、という気付きがあなたのコード品質向上につながればうれしいです。では、楽しいコーディングライフを!