割り算・商
割り算演算子とは /
のことです。商演算子とは \
のことです。
割り算演算子 /
は浮動小数点型の値を受け取り浮動小数点型の値を返す演算子です。浮動小数点型の結果が欲しければ割り算演算子 /
を使います。
商演算子 \
は「整数除算演算子」とも呼ばれます。その名の通り、整数型の値を受け取り整数型の値を返す演算子です。整数型の結果が欲しければ商演算子 \
を使います。
プログラムの読みやすさ、およびプログラムの実行速度の観点からこれらを正しく使い分けることは大切です。 そうしないと「なんでこうしたの?」「なんでこんなに遅いコード書いてるの?」と突っ込まれることになります。
割り算演算子 /
と CInt
を使う?
ところで整数型の割り算の値を得るために、割り算演算子 /
を使いその結果を CInt
で型変換したらダメなのでしょうか?
Dim integerValue As Integer = CInt(integerA / integerB)
ではまず「なぜ CInt
で型変換するのですか?」という問いに自ら答えてみましょう。
CInt
のコストを払うだけの明確な理由があるならば、そうするしかありません。CInt
は四捨五入 (その中の銀行家の丸め banker's rounding) という特殊な、かつ比較的重めの処理をします。銀行家の丸めが本当に必要ならば CInt
で型変換しましょう。重い処理になるのはしょうがありません。これ以上の議論は不要です。
一方明確な理由がないのに CInt
を使うと、コードを書くにも読むにもノイズでしかありません。なんで四捨五入しているんだろう…と戸惑います。そして無駄に重い処理になります。
ちなみに Option Strict Off
だと CInt
を書く必要は無くなりますが、結局 CInt
と同じ処理が入るので無駄に重い処理になるのは変わりません。無駄に重い処理になっていることが隠されるので Option Strict Off
は悪質です。
もう一つコストの話。
最初に説明したとおり割り算演算子 /
は浮動小数点型の値を受け取る演算子です。
ですから、整数型の値同士の演算に割り算演算子 /
を使うと、それら二つの値は浮動小数点型への型変換が入ります。
拡大変換なので、Option Strict On
でも明示的な変換を書く必要はありませんが、確実に処理速度の点ではコストがかかります。
最後にCInt
で浮動小数点型から整数型へまた変換…無駄すぎますよね。
割り算演算子 /
と CInt
を使うと
- 実行速度の点では四捨五入と型変換という余計な処理が入り遅い
- コードの読みやすさの点ではノイズであり人を戸惑わせる
商演算子(整数除算演算子) \
を使う
型を正しく意識していれば、余計な型変換をする必要がなくなります。
Dim integerValue As Integer = integerA \ integerB
型が揃っているので、型変換のコードを書く必要がなく型変換が起こりません。
例え Option Strict On
であったとしても冗長なコードを書く必要はありません。
つまり、コードを書くのも読むのも楽になります。
商演算子(整数除算演算子) \
は小数点以下を切り捨てた整数を返します。銀行家の丸めのように重い処理ではなく、非常にプリミティブな処理で高速です。
さらに整数型から浮動小数点型への余計な型変換をしないのでその分も高速になります。
これら両方が相まってプログラムの実行速度が速くなります。手元で確かめたところ「割り算演算子 /
と CInt
を使う」ケースより「商演算子(整数除算演算子) \
を使う」ケースの方が3倍速くなりました。
商演算子(整数除算演算子) \
を使うと
- 実行速度の点では速くなる
- コードの読みやすさの点では整数型から整数型の商が欲しいことがコードの読み手にストレートに伝わる
コード
Module Program Sub Main() Const n = 100000000 Const times = 5 Dim progression1 = New List(Of Integer)(n) Dim progression2 = New List(Of Integer)(n) Dim r = New Random() For i = 1 To n progression1.Add(r.Next() + 1) progression2.Add(r.Next() + 1) Next Dim answer = New Integer(n - 1) {} Dim s = New Stopwatch() Dim quotient = Sub() s.Restart() For index = 0 To n - 1 answer(index) = progression1(index) \ progression2(index) Next s.Stop() Console.WriteLine($"\ 商演算子 {s.Elapsed}") End Sub Dim division = Sub() s.Restart() For index = 0 To n - 1 answer(index) = CInt(progression1(index) / progression2(index)) Next s.Stop() Console.WriteLine($"/ 割り算演算子 {s.Elapsed}") End Sub Dim speedTest = Sub() quotient() division() End Sub For i = 1 To times speedTest() Next Console.ReadKey() End Sub End Module