コンテンツへスキップ
Topos Uranos

要約

算術式は、読むときのように左から右へ計算されるのではなく、隠れた構造、すなわち式の木に従って計算される。この木を決めるのは演算子の優先順位と結合規則と括弧である。そして木の各ノードでは、オペランドの型がどの演算を行うかを決めるので、7 / 2 は 3 になり、7 / 2.0 は 3.5 になる。このレッスンで学ぶのは、整数と実数に対する C++ の五つの算術演算子、C++11 以降 0 方向に切り捨てる整数除算と余りの演算(ここから、余りは被除数の符号をとり、被除数が負のときはユークリッド除法の余りと異なることが従う)、ユークリッド除法の余りを得る方法、式の木、オペランドの型が異なるときの結果の型、そして整数の算術式が意味を失う二つの場合、すなわちゼロによる除算と途中の計算でのオーバーフローである。

学習目標

  1. C++ の整数除算の商と余りを、負のオペランドの場合も含めて計算し、ユークリッド除法の商と余りと関係づける。
  2. 優先順位と結合規則に従って算術式の木を描き、その値を計算する。
  3. 型の異なるオペランドどうしの演算の結果の型を予測する。
  4. 整数除算と余りを使って量を分解する。数の各桁、時間と分で表した長さ、曜日である。

算術演算子

C++ には二項の算術演算子が五つある。加算 +、減算 -、乗算 *、除算 /、余り % である。さらに、ただ一つのオペランドの符号を変える単項マイナス(-x のように使う)と、オペランドをそのままにする単項プラス +x がある。最初の四つは整数にも実数にも適用され、剰余は整数にだけ適用される。ところが、同じ書き方がいつも同じ演算を表すわけではない。/ の二つのオペランドがともに整数なら、除算は整数除算であり、その結果は整数、すなわち小数部分を除いた商である。どちらかが実数なら、除算は実数の除算である。レッスン 文字・真偽値・型変換・定数 は、この規則の最も目につく帰結を示した。double r{7 / 2}; は 3 を保存する。結果が実数に変換される前に、除算が整数どうしで行われたからである。

例二つの整数に対する五つの演算子

このプログラムは五つの演算子を 17 と 5 に適用し、実数の被除数で除算をもう一度行う。

C++ のプログラム
#include <print>​int main(){    const int a{17};    const int b{5};    std::println("{} + {} = {}", a, b, a + b);    std::println("{} - {} = {}", a, b, a - b);    std::println("{} * {} = {}", a, b, a * b);    std::println("{} / {} = {}", a, b, a / b);    std::println("{} % {} = {}", a, b, a % b);    const double x{17.0};    std::println("{} / {} = {}", x, b, x / b);}
出力
17 + 5 = 2217 - 5 = 1217 * 5 = 8517 / 5 = 317 % 5 = 217 / 5 = 3.4

17 を 5 で割ると 3 になり、2 が余る。これは、17 個の物を 5 個ずつの組に分けるときの商と余りである。最後の行は実数を整数で割り、3.4 を得る。注意すべきことに、std::println は実数 17.0 を「17」と書く。空のプレースホルダは値の最短の表現を書くので、書かれたものからは型がわからない。型を見るには、{:.1f} で小数の桁を求める。

演算子 % は実数を受けつけない。7.5 % 2 と書くことは、プログラムが実行時に見つける論理エラーではなく、コンパイルエラーである。コンパイラは、型 double と int のオペランドはこの演算子には不正だと告げる。

C++ のプログラム
#include <print>​int main(){    std::println("{}", 7.5 % 2);}
コンパイラのエラーメッセージ
main.cpp: In function ‘int main()’:main.cpp:5:28: error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’    5 |     std::println("{}", 7.5 % 2);      |                        ~~~ ^ ~

実数の除算の余りは存在し、ヘッダ <cmath> の関数 std::fmod がそれを計算する。この関数はレッスン ビットと数学ライブラリ でべき乗とともに学ぶ。C++ にはべき乗の演算子がなく、2 ^ 3 は 8 ではなく別のものになるが、それもそこで説明する。