なぜ、演算子が重要なのか、その理由

この記事では、当社の新人エンジニア研修の参考にC#を解説します。

前回は「変数でデータを再利用できるようになる」について学びました。

今回は演算子を解説します。コンピュータ(Computer)の語源は「計算してくれる人」であると言われます。そのため、計算処理(演算子の活用)はプログラムの本質的な役割の一つと言えます。

C#には様々な演算子がありますが、ここでは特に下記を解説します。

  • 算術演算子
  • キャスト演算子

(関係演算子・条件演算子・三項演算子などは、次回以降の「条件分岐と判定条件」で解説予定です。)

1. 算術演算子

四則演算(+、-、×、÷)などを行う演算子を「算術演算子」といいます。例として、C#で足し算をする簡単なサンプルを見てみましょう。

using System;

namespace Chap03
{
    public class Example01
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(5 + 2);
        }
    }
}

このプログラムを実行すると、コンソールには 7 と出力されます。このときの「+」記号を演算子(operator)と呼び、52 のことを被演算子(operand)と呼びます。また、 5 + 2 は「7」という値を持つため(expression)と呼ばれます。さらに、Console.WriteLine(5 + 2); のようにセミコロン; まで含めたものを(statement)と呼びます。

この「+」が足し算を意味するので、「算術演算子」として分類されます。C#における主な算術演算子は以下のとおりです。

算術演算子演算内容式の例結果(値)
+足し算5 + 27
-引き算5 - 23
*掛け算5 * 210
/割り算5 / 22
%剰余(余りを求める)5 % 21

整数同士の割り算に注意

5 / 2 は 2.5 ではなく 2 になります。整数同士の演算結果は整数となり、小数点以下は切り捨てられます。

算術演算では掛け算・割り算(%含む)が足し算・引き算より先に計算されることも数学と同じです。

実験

結果はどうなるでしょうか?

Console.WriteLine(1 + 5 % 2);

Console.WriteLine((1 + 5) % 2);

今日は何曜日ですか? 100日後は何曜日でしょう?

  • 曜日は7日周期で繰り返すため、 100 % 7 で余りを計算するとヒントになります。

2. 変数を含む式

にはリテラルだけでなく変数を含めることもできます。以下のExample02は「1に1を足した数」から始まって、さらに1ずつ増やしていく例です。

using System;

namespace Chap03
{
    public class Example02
    {
        public static void Main(string[] args)
        {
            int i = 1;
            int j = i + 1;
            Console.WriteLine(j);

            j = j + 1;
            Console.WriteLine(j);

            Console.WriteLine(j += 1);    // 短縮表記の例1

            Console.WriteLine(++j);      // 短縮表記の例2 => j += 1; Console.WriteLine(j);
            Console.WriteLine(j++);      // 短縮表記の例3 => Console.WriteLine(j); j += 1;

            Console.WriteLine(j);
        }
    }
}

<実行結果>

2
3
4
5
5
6
  1. int j = i + 1;
    数学での「=」は「等しい」という意味ですが、プログラミング言語の「=`」は**「右辺の値を左辺(変数j)に代入する」**という意味です。算数の「==」とは違うので注意しましょう。
  2. j += 1;複合代入演算子の1つで、 j = j + 1; と同じ効果です。

複合代入演算子の書き方

複合代入演算子は式を短く記述するために使用する記法です。

number -= 2; 
number *= 2; 
number /= 2; 
number %= 2;
新人エンジニア
複合代入演算子の書き方

いずれも number = number - 2; のように書くより簡潔にできます。変数名が長いと特に助かります。

インクリメント / デクリメント

  1. ++j / j++ は、変数 j を1増やす命令(インクリメント)。
  2. --j / j-- は、変数 j を1減らす命令(デクリメント)。

前置と後置

  • 前置 (++j) : 式の中で「増やした後」の値が使われる
  • 後置 (j++) : 式の中で「増やす前」の値が使われる

単独の行で j++; と書く場合は前置も後置も結果は同じです。

3. 変数の型と代入の制限

前回、変数には型があり、代入できる数値の範囲や型が決まっていると学びました。では、例えば double 型の変数に int 型の整数を代入するとどうなるでしょう?

using System;

namespace Chap03
{
    public class Example03
    {
        public static void Main(string[] args)
        {
            double d = 1;
            Console.WriteLine(d);
        }
    }
}

<実行結果>

1

C#ではこれが暗黙の型変換(implicit conversion)となり、エラーにはなりません。「より大きな表現範囲を持つ型」に代入する場合、コンパイラが自動で拡張変換してくれます。

しかし、逆にdoubleintのように精度を失う可能性がある代入は、自動では行われません。以下はエラーになります。

using System;

namespace Chap03
{
    public class Example04
    {
        public static void Main(string[] args)
        {
            int i = 3.14;
            Console.WriteLine(i);
        }
    }
}

<エラーメッセージ例>

Cannot implicitly convert type 'double' to 'int'

これを可能にするのがキャスト演算子です。

4. キャスト演算

より小さな型に強制的に変換(ダウンキャスト)する場合は、丸カッコを使ったキャスト演算子で明示します。

using System;

namespace Chap03
{
    public class Example05
    {
        public static void Main(string[] args)
        {
            int i = (int)3.14;
            Console.WriteLine(i);
        }
    }
}

<実行結果>

3

小数点以下が切り捨てられました。

新人エンジニア

キャスト(cast)とは、「ある型のデータを、別の型として解釈・振る舞わせる」ことです。映画やドラマで「役者をキャスティングする」といえば、役に当てはめることを指しますが、プログラミングでも似たイメージで捉えられます。

混在した型を計算すると?

下記プログラムでは intdouble が混在していますが、結果はどうなるでしょう?

using System;

namespace Chap03
{
    public class Example06
    {
        public static void Main(string[] args)
        {
            int i = 1;
            double d = 3.1;
            Console.WriteLine(i + d);
        }
    }
}

<実行結果>

4.1

より大きな型(double)に合わせて計算され、結果も double 型になります。

整数同士の割り算を小数で出したい場合

Console.WriteLine(5 / 2);        // 結果は 2
Console.WriteLine(5 / 2.0);      // 2.5 (5はint, 2.0はdouble → 結果double)
Console.WriteLine(5 / (double)2);// 2.5

いずれかのオペランドをdouble(もしくはfloat)にキャストすれば、小数を含む結果が得られます。

暗黙の型変換が働くパターン

C#では、ビット幅が広い型へは暗黙的に代入可能(例:intlongfloatdouble)、それ以外は明示的にキャストが必要です。charshort は符号・表現が異なるため、暗黙変換が自動的に入らない場合があります。

5. DivideByZeroException

using System;

namespace Chap03
{
    public class Example07
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(5 / 0);
        }
    }
}

これはコンパイルこそ通りますが、実行時に

System.DivideByZeroException: Attempted to divide by zero.

という例外(Exception)が発生してプログラムが停止します。

例外(Exception)とは、プログラム実行中に起こる異常事態です。

「0で割る」という操作は数学的に未定義であるため、C#ではDivideByZeroException を発生させます(int除算の場合)。

  • 一方、浮動小数点型 (double, float) での 0除算は InfinityNaN を返します。

このように、意図しないところで0除算が起こると実行時にエラーになります。現場では「もし割る数が0だったら何もしない(あるいは例外処理を行う)」といった対策を行います。

例外は決して嫌うべきものではなく、エラーが起きたときに教えてくれるありがたい仕組みだと考えましょう。C言語のように「結果が未定義」のまま暴走するより安全です。

6. 文字列の結合に使用する「+」

C#でも、文字列は string 型の変数に代入できます。

using System;

namespace Chap03
{
    public class Example08
    {
        public static void Main(string[] args)
        {
            string str = "Hello World";
            Console.WriteLine(str);
        }
    }
}

文字列については、後の章で詳しく学びます。

文字列同士の連結

using System;

namespace Chap03
{
    public class Example09
    {
        public static void Main(string[] args)
        {
            string str1 = "Hello";
            string str2 = " World";
            Console.WriteLine(str1 + str2);
        }
    }
}

<実行結果>

Hello World

「+」が足し算とは違い、文字列の連結を行います。

文字列と数値が混在する場合

using System;

namespace Chap03
{
    public class Example10
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("1 + 2 = " + 1 + 2);
            Console.WriteLine(1 + 2 + " は 1 + 2 の答えです");
        }
    }
}

<実行結果>

1 + 2 = 12
3 は 1 + 2 の答えです

これは「演算子が左から順に結合(左結合)」されるため、最初の例では "1 + 2 = "(文字列) と 1 を結合した結果が "1 + 2 = 1" となり、さらに + 2 が文字列連結となって "1 + 2 = 12" になります。

2つ目は (1 + 2) = 3 の計算が先に行われた後、 "3 は~" という形になるので 3 と出力されます。

新人エンジニア
左から順に結合(左結合)


文字列結合と算術演算が混在する場合は、意図しない結果を防ぐためカッコ( )を使って計算順序をはっきりさせるとよいでしょう。


<まとめ:隣の人に正しく説明できたらチェックを付けましょう>

□ 算術演算子は + - * / % の5種類である

□「=」は代入を意味し、算数の「等しい」ではない

□より大きな型への代入は暗黙変換が可能だが、より小さな型にはキャストが必要

□ 演算子は左結合なので、文字列と数値計算が混在するときは注意("1 + 2 = " + 1 + 2 など)

次回は、「4章. 条件分岐で場合に応じた処理ができるようになる」を学びます。

最後までお読みいただきありがとうございます。