コンピュータで割り算したい
コンピュータで割り算したい
掛け算はネットによく出る形で計算すればよいので簡単だが、割り算を行う場合は何かと面倒。
まず掛け算を考える。
方針として、シフト演算を行うことで、2^n倍の計算ができることと、2x + 3x = 5*xのように同じ数値への掛け算は係数を足し合わせることでまとめることができることを用いる。
2^n * x を使って各桁で掛け算をした結果を足し合わせることで掛け算を実装する。
例として、12 * 3を考える。
0b0011(2進数で3)は、2^nを使って、0 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 * 2^0 = 1 * 2^1 + 1 * 2^0 = 3 と表せる。
3 = 1 * 2^1 + 1 * 2^0 より
12 * 2^1 + 12 * 2^0 を計算すればよい。
2^nの形はシフト演算を行うことで計算できる。
よって、左シフト演算子(<<)を使って、上記の式は、
(12 << 1) + (12 << 0) と表せる。
これを計算すると、24 + 12となり、36が求まる。
(なんか回りくどい上に正確性に欠けている気がする。)
割り算の場合は逆演算をしてやればいいはずである…?
左シフトをした後に足しているので、減算した後に右シフトすればよい…?
13 を 5で割ることを考える。コンピュータで割れるように機械的なプロセスが望ましい。
これを考える。
減算する値は、5に2^nをかけた値のはずなので、5 * 2^nを考える。
また、減算した後の値は0に近づくはずである。なぜなら、掛け算する際に0
に足しているため、逆演算した後なら0になっているはず…?多分。
また、なるべく大きい値で減算したいため(除数を100回割るようなことは避けたい)、除数 * 2^nのnが最も大きくなるかつ、被除数から除数*2^nを減算した際に0に近づくようにしたい。
上記の条件を満たし、13を越えない、52^nを満たすようなnは1である。そのため、結果の2ビット目が1であることがわかる。
13 - 52^n = 3
3に対して、同様に確認を行うと、これを満たすような数値はない。
つまり、13 / 5 の結果は 2(2ビット目が1) あまり 3となる。
数値が0にならないのは私にとって少しだけ違和感があるが、
13 / 5 = xから
13 = x * 5のように変形する。
すると、13 = x * 5 を満たすような整数は存在しないことがわかる。
そのため、あまりがあっても問題ない…?
上記のプロセスをプログラミングに落とし込む。
色々端折ってCでフローを記載する。(mainは記載していない。)
// A / B を計算する。
// 32 bitコンピュータ
int div(int A, int B)
{
int result = 0;
for (i = 32 - 1; i >= 0; i++)
{
if (A > (B << i))
{
A = A - (B << i);
result += 1;
}
result <<= 1;
}
return result;
}
何とか実装できた。
結局、一回unsigned型に直して計算するのしかできなかった。signedのまま計算する方法はようわからんぬ。