『負数』の『除算・剰余』と『プログラミング』
負数(マイナスの値)を含む演算においての割り算や、その余りの計算結果を意識したことがあるでしょうか?
例えば、乗算のように、『式に負数があれば結果も負数、正数ならば結果も正数』だと思っていませんか?
負数の除算・剰余がどんな結果になるのか、実際にプログラムを交えて紹介していきます。
目次
意図しない負数の除算・剰余は避けよう
さっそく結論です。
負数の除算・剰余を避けたい理由はズバり、『プログラミング言語によって負数の剰余式の結果が異なる』ためです。
プログラミング言語によって負数の除算・剰余の結果が異なる。
なので、意図しない負数の剰余式が発生しないようプログラミングすることは、バグを回避することにもつながるわけです。例えば、マルチプラットフォーム開発においては、異なるデバイスで同じ動作をさせる目的で、複数の言語を用いたりするので、こういった違いには敏感にならなければいけませんね。
以下は、検証とまとめです。
プログラミング言語による剰余の違い
様々なプログラミング言語で、剰余と除算の結果をまとめてみました。
除算式としては、-1 を 3 で割った結果を、剰余式としては -1 を 3 で割ったときの余りを求めました。※除算式では、整数計算できる場合は整数で求めています。
言語とバージョン | 除算式 | 商 | 剰余式 | 余り |
---|---|---|---|---|
C++(gcc11.0) | -1 / 3 | 0 | -1 % 3 | -1 |
C++(Clang12.0) | -1 / 3 | 0 | -1 % 3 | -1 |
C++(MSVC2019) | -1 / 3 | 0 | -1 % 3 | -1 |
C#(mcs5.19) | -1 / 3 | 0 | -1 % 3 | -1 |
Java(jdk-11) | -1 / 3 | 0 | -1 % 3 | -1 |
Go(1.14) | -1 / 3 | 0 | -1 % 3 | -1 |
R(3.5) | -1 %/% 3 | -1 | -1 %% 3 | 2 |
Python(2.7) | -1 / 3 | -1 | -1 % 3 | 2 |
Python(3.8) | -1 // 3 | -1 | -1 % 3 | 2 |
PHP(7.3) | -1 / 3 | -0.33… | -1 % 3 | -1 |
Perl(5.33) | -1 / 3 | -0.33… | -1 % 3 | 2 |
JavaScript(Node.js 14.0) | -1 / 3 | -0.33… | -1 % 3 | -1 |
TypeScript(3.9) | -1 / 3 | -0.33… | -1 % 3 | -1 |
Ruby(2.6) | -1 / 3 | -1 | -1 % 3 | 2 |
Ruby(2.6) | -1.div(3) | -1 | -1.modulo(3) | 2 |
Ruby(2.6) | -1.div(3) | -1 | -1.remainder(3) | -1 |
SQL(sqlite3.34) | -1 / 3 | 0 | -1 % 3 | -1 |
SQL(MySQL8.0) | -1 / 3 | -0.33… | -1 % 3 | -1 |
VBA(7.1) | -1 / 3 | 0 | -1 Mod 3 | -1 |
VB.Net(16.0) | -1 \ 3 | 0 | -1 Mod 3 | -1 |
COBOL(paiza.io) | -1 / 3 | なし | FUNCTION MOD(-1 3) | 2 |
Kotlin(1.3) | -1 / 3 | 0 | -1 % 3 | -1 |
Objective-C(2.0) | -1 / 3 | 0 | -1 % 3 | -1 |
Swift(5.0) | -1 / 3 | 0 | -1 % 3 | -1 |
Swift(5.0) | -1 / 3 | 0 | -1.remainder(dividingBy: 3) | -1.0 |
Lua(5.4) | -1 // 3 | -1 | -1 % 3 | 2 |
Scratch(3.0) | -1 / 3 | -0.33… | -1を3で割った余り | 2 |
様々なプログラミング言語で剰余式を確認してみると圧巻ですね…
さて、結果を踏まえてた上で注目しておきたい点は以下になります。
- コンパイラやバージョンが違っても結果は同じ
- 静的・動的型付言語に依存するわけでもない
- 複数の算出方法を提供する言語もある
- 商が0、余りが-1のパターンと、
商が-1、余りが2のパターンがほとんど
共通点を探してみましたが、これといって法則があるわけでもなさそうです。
割り算の余りをおさらい
お次は、一度プログラミングから離れて、純粋な算数としての割り算を振り返ってみましょう。
割り算と余りの公式
(割られる数)÷(割る数)は(商)と(余り)
小学校で習う、割り算と余りの公式ですね!(実際に公式と呼んでいたかはうろ覚えですが…)
例えば『7 ÷ 3』という式を実際に割り当ててみると…
(割られる数)÷(割る数)は(商)と(余り)
と、上記のようになり、ほとんどのかたには違和感のない式になっていると思います。
割り算と余りを等式で表現
(割られる数)=(割る数)×(商)+(余り)
先ほどの割り算の公式を、両辺が等しくなるように商と余りを含めた計算式に組み替えると、上記のような等式が成り立ちます。
同じように『7 ÷ 3』の式を割り当ててみると…
(割られる数)=(割る数)×(商)+(余り)
バッチリ等式で決まりましたね!
負数の除算・剰余で正しい答えを証明する材料が整いました!
負数の除算・剰余を証明
(割られる数)=(割る数)×(商)+(余り)
先ほど紹介した、上記の等式を使っていきます。
そして、改めて除算と剰余の結果をまとめます。
答1:商が0、余りが-1
答2:商が-1、余りが2
ほとんどが、上記の二通りでしたね。
では、等式に除算と剰余の結果を当てはめてみましょう!
(割られる数)=(割る数)×(商)+(余り)
(割られる数)=(割る数)×(商)+(余り)
どちらのパターンも等式が成り立ってしまいました…
つまり、解としてはどちらも間違ってはいないということです。
やはり負数の除算・剰余は避けよう
まとめです。
本記事で伝えたいことは、数学的な証明というよりあくまで『負数の除算・剰余で結果が違うプログラムがある』ということです。
さらに検証を続けるならば、割られる数が負数のケース、割る数が負数のケースと、それぞれのパターンも掘り下げるべきでしょう。
実際のところ、プログラミングは『言語の規約』と『実行結果』が全てなので、どういった結論であれ、多くのプログラマーはそれに従うことになります。
言語によって性質が違うことを素直に受け入れられるか、否定するかでモノの考え方も変わってきます。本記事で、広く寛容な考え方ができるようになればとも願って書いてみました!
以上、『負数』の『除算・剰余』と『プログラミング』でした。