わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

マイナス5÷3は?

いきなりですが問題です.

5÷3は,いくつでしょうか?

これって,小学校の算数ですね.とはいえ,小学校で学習した中でも,答えは何通りか言うことができて,分数にするなら,\frac{5}{3}だとか,帯分数にして1\frac{2}{3}だとか.小数で表すなら,1.666…ですね.
あまりのあるわり算だったら,商は1で,あまりは2です.「5÷3=1…2」と書いていたのでしたっけ.
ここでは,商とあまりを求めることを,前提とします.わる数もわられる数も,商もあまりも,整数です.
といったところで本題です.

-5÷3は,何あまり何でしょうか?

わられる数がマイナス,というのは,中学校で,学習したでしょうか.
-5÷3については,商とあまりの組み合わせの候補が,2つあります.数直線を使うと,その違いが分かりやすくなります.

ひとつは,商を-1にします.原点から-5にたどり着くために,3を「-1倍」するというわけです.左方向に,いち,おしまいです.にぃ,と行ったら-5を越えてしまうので,行きません.
なのですが,いち,でたどり着いた地点は-3です.-5には届いていません.-5に行き着くために,「-2」をたします.式にすると,3(-1)+(-2)=-5となります.
ということで,「商は-1,あまりは-2」とするのが,商とあまりの候補の1組目と言えます.
別のアプローチは,商を-2にします.原点から-5に行き着くために,3を-1倍するのでは届かないので,「-2倍」します.左に,いち,にぃ,ですね.すると,-6に来ます.-5を越えてしてしまいました.
そこから-5に行くには,1だけ右へ行く…「1」をたせばいいわけです.
式だと,3(-2)+1=-5です.2番目の候補は,「商は-2,あまりは1」です.


どちらが正しいのでしょうか? どちらを採用すべきでしょうか?
整数÷整数という式で…ただしわる数は0ではないものとします,そして,わられる数もわる数も,プラスでもマイナスでもいいとしますが…「商と剰余の基本要件」というのが定まります.a を b で割ったときの商が q,あまりが r のとき,次の2つをともに満たすことです.

  • a=bq+r
  • 0≦|r|<|b|

縦棒2本は,絶対値の記号です.
1つ目の式,a=bq+rは,中学校で学習したのではないでしょうか.マイナスの数になっても,この等式は同じです.
2つ目の式は,aもbも正だったら,絶対値記号がそのまま外せます.しかしbが負の数だったら,そうもいかないので,絶対値をつけておきます.なお,0≦|r|の等号が成り立つときというのは,r=0で,これは,aがbでわり切れることに対応します.一方,右側の不等号は,「≦」ではなく「<」です.r=±b,とはならないからです.
-5を3でわったとき,「商は-1,あまりは-2」「商は-2,あまりは1」は,いずれもこの基本要件を満たします.


そして,「商と剰余の追加要件」というのを考えます.追加要件は2種類あって,どちらかを採用します.そしてそれによって,商とあまりの組み合わせが1つになります.
追加要件の1つは,わり切れない場合,わられる数とあまりの符号を同じとします.
わり切れる場合も合わせて,言うと,わられる数が正なら,あまりは0以上となり,わられる数が負なら,あまりは0以下となります.
これは,GCCや多くのCの処理系で採用されています.
この追加要件を採用するなら,-5÷3の「商は-1,あまりは-2」です.
それと別の追加要件は,aが0より大きいか小さいか,bが0より大きいか小さいかにかかわらず,rは必ず0以上,です.先ほどの絶対値記号のうち,rのほうを取り除いて,0≦r<|b|となります.
RSA暗号アルゴリズムを手計算で考える際には,こちらを採用します.
そしてその場合,-5÷3の「商は-2,あまりは1」となります.
どちらが正解,どちらが間違いというのではなく,条件が緩ければ,その条件を満たす答え(商とあまり)が複数考えられ,厳しくすれば,ひとつに定められる,ということだったのです.


それぞれの整数を3でわったときのあまりを,数直線に乗せると,次のようになります.

数直線の下の数値は,0の近辺の整数です.実際には,もっともっと左にも右にも伸ばせます.数直線の上の数値のうち,上の段は,追加要件の先に書いたほう,わられる数とあまりの符号が同じというときの,あまりです.下の段は,追加要件の2つめのほう,あまりは必ず0以上という場合です.
青の数字は,わられる数が正負関係なく,0,1,2,0,1,2,となっていますね.わる数bが任意の正の数であってもこれは成立します.こういうのを,整数全体の集合を,b個の剰余類に分けると言います.


Cのプログラムで,負の数aを正の数bで割ったときに,2番目の追加要件を満たすよう,常に非負の余りを得るには,どうすればいいでしょうか?
わられる数の符号を取り除いてから,わり算してあまりを出すというのは,ダメです.5÷3のあまりは2なのに対して,-5÷3のあまりは,-5=3(-2)+1に注意すると,1でないといけないからです.
式はいろいろ書くことができますが,(a%b+b)%bが一番単純でしょうか.%はCの剰余演算子です.aに-5,bに3を代入して,確かめてみますと,(-5%3+3)%3=(-2+3)%3=1%3=1となります.
外側の「%b」は,aがbでわり切れる場合に0にするため必要で,これがないと,-6を3でわったときのあまりが,0ではなく,3になってしまいます.

なにこれ

例年,情報セキュリティで,RSAに関連するアルゴリズム(べき剰余,拡張ユークリッド互除法)を取り上げる際に,加減乗除と剰余を説明したあと,負の数を正の数でわったときのあまりの扱いについて,2枚のスライドを設けて詳しく解説してきました.
本記事では,その詳細化を図ってみました.