give IT a try

プログラミング、リモートワーク、田舎暮らし、音楽、etc.

割り算の結果に要注意・・・!!

不思議な現象?

さて、いきなり問題です。


「6÷5」はいくつでしょうか??


・・・ほとんどの人は「1.2」と答えるのではないでしょうか?


では以下のSQLの実行結果はいくつになるでしょうか?

select 6 / 5


・・・実は「1」になります。


プログラミング言語によっては、整数同士の割り算の結果を整数で返す言語があります。


ただ、紛らわしいことに言語によって結果は非常にまちまちです。


SQL Serverは「1」を返しますが、Oracleは「1.2」を返します。
C#も「1」を返しますが、Perlは「1.2」を返します。


割り算が発生するロジックを扱う場合、自分の使っている言語がどちらのタイプなのか十分注意してください。
プログラミングの初歩の初歩みたいな話ですが、これが原因でしょうもないバグが発生したりすることもあります。

対策

さて、「1」ではなく「1.2」という結果がほしい場合、SQL ServerC#ではどうしたらよいでしょうか?


この場合、実数型の値を混ぜ込んで「扱いたいのは整数じゃなくて実数ですよ」ということを明示的に表明してください。


たとえば、どちらかの値に「.0」を付ける方法があります。

-- OK: 1.2
select 6.0 / 5

-- OK: 1.2
select 6 / 5.0


ただし、変数やカラム名には「.0」を付けられません。
そこで明示的に型変換を行う方法もあります。

-- OK: 1.2
select convert(float, 6) / 5

-- OK: 1.2
select 6 / convert(float,5)


最初に1.0をかけてしまう方法もあります。個人的にはこの方法がシンプルで好きです。

-- OK: 1.2
select 1.0 * 6 / 5


ただし、後ろに1.0をかけてしまうと「1」になってしまうので要注意です。
(整数÷整数×実数 → 整数×実数 = 1×1.0 になっていると思われる)

-- NG: 1
select 6 / 5 * 1.0


C#でもほぼ同様のテクニックが使えます。

// NG: 1
Console.WriteLine(6 / 5);

// OK: 1.2
Console.WriteLine(6.0 / 5);

// OK: 1.2
Console.WriteLine(6 / 5.0);

// OK: 1.2
Console.WriteLine((float)6 / 5);

// OK: 1.2
Console.WriteLine(6 / (float)5);

// OK: 1.2
Console.WriteLine(1.0 * 6 / 5);

// NG: 1
Console.WriteLine(6 / 5 * 1.0);


プログラミングする際はこういった挙動の違いに十分注意してくださいね。