【コピペでUnity】割り算の実装ミスを一撃で解決します

Unity
Unity

割り算がよく分からなくなった人

余りのある割り算って%でいいんだよね?
あれ、割り算の答えがおかしい…。
マイナスの割り算ってどうすればいいの?

 

ひとまず割り算の記述パターンはこちらです。

//整数の割り算、商を整数で得る
_int = _intA / _intB
//整数の割り算、余りを整数で得る
_int = _intA % _intB

//整数の割り算、商を小数で得る
_float = (float)_intA / (float)_intB;
//整数の割り算、余りを小数で得る、ほぼ意味がない
_float = (float)_intA % (float)_intB;

//少数の割り算、商を小数で得る
_float = _floatA / _floatB
//少数の割り算、余りを小数で得る
_float = _floatA % _floatB

//少数の割り算、商を整数で得る
_int = (int)_floatA / (int)_floatB;
//少数の割り算、余りを整数で得る
_int = (int)_floatA % (int)_floatB;

 

本記事の内容

●割り算サンプルコード解説
●割り算の商を求める、除算演算子
●割り算の余りを求める、剰余演算子

 

この記事を書いている私は12才からフルスクラッチでゲームを作っています。
またコンパイラを専門として情報理工学の博士まで進学、中退をしており、プログラミング言語の文法にも関わる論文を書いていました。

実用数学技能検定1級も所持しています。

 

※実行環境
Unity2021.3.1f1
Windows 10

 

割り算サンプルコード解説

●_intA, _intB
割り算をしたい2つの整数
●_floatA, _floatB
割り算をしたい2つの小数

●_int
割り算の整数値
●_float
割り算の小数値

●(int)
int型への変換、キャストと呼ぶ
●(float)
float型への変換、キャストと呼ぶ

 

割り算の実行例

整数同士の割り算

●7 / 3…2
●7 / -3…-2
●-7 / 3…-2
●-7 / -3…2
●7 % 3…1
●7 % -3…1
●-7 % 3…-1
●-7 % -3…-1

 

小数にキャストした整数同士の割り算

●7 / 3…2.333333
●7 / -3…-2.333333
●-7 / 3…-2.333333
●-7 / -3…2.333333
●7 % 3…1
●7 % -3…1
●-7 % 3…-1
●-7 % -3…-1

 

先述の通り、整数同士の割り算だと余りを小数で求めたところで恩恵は少ないですね。
もしかしたらCPUレベルで計算の命令が置き換わったりするかもしれませんが、最近のコンパイラだとそういうコードも最適化してくれそうです。

 

小数同士の割り算

●3.14f / 2.71f…1.158672
●3.14f / -2.71f…-1.158672
●-3.14f / 2.71f…-1.158672
●-3.14f / -2.71f…1.158672
●3.14f % 2.71f…0.4300001
●3.14f % -2.71f…0.4300001
●-3.14f % 2.71f…-0.4300001
●-3.14f % -2.71f…-0.4300001

 

小数の末尾にあるfはfloat型の数値を表します。
ないとdouble型を意味します。

 

整数にキャストした小数同士の割り算

●3.14f / 2.71f→3 / 2…1
●3.14f / -2.71f→3 / -2…-1
●-3.14f / 2.71f→-3 / 2…-1
●-3.14f / -2.71f→-3 / -2…1
●3.14f % 2.71f→3 % 2…1
●3.14f % -2.71f→3 % -2…1
●-3.14f % 2.71f→-3 % 2…-1
●-3.14f % -2.71f→-3 % -2…-1

 

小数を(int)を用いてキャストすると、絶対値が小さくなる方向、ゼロ方向の丸めで処理されます。

 

ただの割り算なのになぜ分からなくなるかというと、結局はこういった細かい基礎が曖昧なままになっているだけだと思います。
そう思えばあとはひとつひとつ知っていくだけなので安心ですね。

 

割り算の商を求める、除算演算子

なぜこのような挙動になるのかは、もう少し深く考えてみることで解決します。
せっかくなので掘り下げてみましょう。

割り算の単純なアルゴリズムは、符号が変わるまで引き算を続けることです。

 

7 / 3を整数で求めるアルゴリズム

①7から3を1回引くと4
②7から3を2回引くと1
③7から3を3回引くと-2、これは不適
④よって7 / 3 = 2

「7 / -3」の場合は1回引くと10になってしまうので、引く回数の方を工夫します。
-1回引くと考えれば4になるので-2回引くと1、-3回引くと-2になってしまうため最終的には「7 / -3 = -2」と考えることが出来ます。

これは小数に対しても同じように考えることが出来ます。

 

7 / 3を小数で求めるアルゴリズム

①7から3を1回引くと4
②7から3を2回引くと1
③7から3を2.3回引くと0.1

こんなノリで1回の引き算をいくらでも小さくすることが出来るため、小数で商を求める割り算は符号を変えずに割り続けることが出来ます。

 

割り算の余りを求める、剰余演算子

同じように余りのある割り算を実現する剰余演算子についても見ていきましょう。

と、ここまで気になる方にはむしろ調べ方からお教えします。
C#の公式な定義を見てみましょう。

算術演算子 - C# リファレンス
数値型を使用して乗算、除算、剰余、加算、減算の演算を実行する C# 演算子について学習します。

 

整数の場合は

a – (a / b) * b

と書かれています。

 

「7 % 3」を整数で求めるアルゴリズム

①7 / 3を計算する
整数なので、2が計算されます②2 * 3を計算する
6が計算されます

③7 – 6を計算する
1が計算されます

 

余りの定義は以下の通りです。

$$割られる数 = (商 * 割る数) + 余り$$

剰余演算子は余りを求める演算子なので式変形をして、

$$余り = 割られる数 – (商 * 割る数)$$

と表現できます。

 

一方で、

$$商 = 割られる数 / 割る数$$

より代入をして、

$$余り = 割られる数 – (割られる数 / 割る数) * 割る数$$

と求まります。

 

ここで、

$$\begin{align}
割られる数 &= a \\ 割る数 &= b
\end{align}$$

とすると、そのまま代入をして、

$$余り = a – (a / b) * b$$

のように引用した式を求めることが出来ました。

 

小数、浮動小数点の場合も同様の発想です。
もちろん小数は割り続けることも出来てしまうので、小数の余りのある割り算は商を整数で計算する点だけ注意しましょう。

 

慣れてきたらこのように、言語の公式情報を見るのも選択肢のひとつです。
習得速度がかなりアップすると思います。

割り算の実装やバグをキッカケに、何か深みにハマるキッカケになれば幸いです。

 

今回は以上です。

Unityはいいぞ。

コメント

タイトルとURLをコピーしました