31.7 条件と真偽値

2 次方程式 “ax2+bx+c=0” は,a, b, c の値によって(実数範囲での)解が 2 つだったり,1 つだったり,1 つもなかったりします.

  • “x2-5x+6=0” は 2 個
  • “x2+2x+1=0” は 1 個
  • “x2+2x+2=0” は 0 個

といった具合です.

この解の個数は,判別式が正,負あるいはゼロになることで区別できることはよく知られていますね.例えば,“x2-5x+6=0” は判別式の値 “discriminant(1, -5, 6)” が “1.0” と正になるので,解が 2 個あることが分かります.

プログラムではこのような条件の判断も計算の一種として扱います.例えば「判別式が正であるか」という条件の判断は,次のようにして行うことができます.

// Program.java: 解を 2 つ持つかの判定 class Program { public static double square(double x) { return x * x; } public static double discriminant(double a, double b, double c) { return square(b) - 4 * a * c; } public static void main(String[] args) { System.out.println(discriminant(1, -5, 6) > 0.000001); } }
true

この例で “discriminant(1, -5, 6) > 0.000001” は,“2.0 * 3.0” などと同様に計算式です.掛け算を表わす “*” という演算子のかわりに,数の大小を比較する “>” という記号が使われている点だけが違いです.

なお, “0” ではなく “0.000001” という数と比較しているのは,計算誤差に対処するためです.計算機の小数計算では,重解を持つような場合でも判別式がぴったり 0 にはならず,0 に近い非常に小さな値となる場合があります.そのような 0 に非常に近い値は “0” とみなしたほうが適切な判断になっていることが期待できます.“0.000001” と比べれば,解が 2 個あると判断してしまうことを避けられる訳です.

一方,計算結果は数値ではなく “true” と出力されています.これは日本語にすると「真」つまり,「“discriminant(1, -5, 6)” は “0.000001” より大きい」という条件は「正しい」という結果だったことを表わしています.逆に「正しくない」つまり「偽」の場合は “false” と出力されます.

このように,といっても “true” と “false” だけですが,条件の判断結果を表す値を真偽値といいます.さらに真偽値には演算があるため,条件を組み合わせてできる条件(「A または B」など)に対応できます.

条件と真偽値のまとめ

条件と真偽値,そしてその計算についてまとめておきます.ただし,ソースコードのうち “Program” と “main” の部分を省略しています.

  • “true” または “false” と書くと真偽値と見なされます.
    System.out.println(true);
    

    true
  • 真偽値は整数・小数の比較演算子 “==”, “!=”, “<”, “>”, “<=”, “>=” によって得ることができます.それぞれ「等しい」,「等しくない」,「より小さい」,「より大きい」,「以下」,「以上」を表します.「等しい」は “=” ではなく “==” です.
    System.out.println(0 < 1);
    System.out.println(3.9 == 2.0 * 2.0);
    System.out.println(8.0 > 2);
    

    true false true
  • 条件の「かつ」や「または」を表す条件(真偽値)はそれぞれ “&”, “|” という演算子を使います.なお,“&&”, “||” を使うことで結果が確定した段階で計算を終わらせることができます.また,条件の否定「でない」を表すには “!” を関数のように使います.
    System.out.println(true & false);
    System.out.println((3 < 5) || (4.7 == 2.1));
    System.out.println(!(1.5 > 0) && !(1.5 < 0));
    

    false true false

真偽値の利用

「2 次方程式 “ax2+bx+c=0” が解を 2 つ持つ」という条件の判断に “two_roots” という名前を付けてみましょう.真偽値も値の一種ですから,変数や関数にすることができます.その時の値の種類は “boolean” と書きます.

// Program.java: 解を 2 つ持つかの判定 class Program { public static double square(double x) { return x * x; } public static double discriminant(double a, double b, double c) { return square(b) - 4 * a * c; } public static double eps = 0.000001; // 十分小さい数を用意 public static boolean two_roots(double a, double b, double c) { return discriminant(a, b, c) > eps; } public static void main(String[] args) { System.out.println(two_roots(1, -5, 6)); System.out.println(two_roots(1, 2, 1)); System.out.println(two_roots(1, 2, 2)); } }
true false false

同様にして,「解を 1 つも持たない」に “no_roots” という名前を付けます.

public static boolean no_roots(double a, double b, double c) {
  return discriminant(a, b, c) < -eps;
}

「重解を持つ」は,「解を 2 つは持たない」かつ「『解を1  つも持たない』ではない」場合です.この判断に “one_root” という名前を付けて定義すると,次のように書くことができます.

public static boolean one_root(double a, double b, double c) {
  return !(two_roots(a, b, c)) && !(no_roots(a, b, c));
}

ちょっと複雑な式になってしまいましたが,上に示した通りの意味になっているのがわかると思います.

なお,“&&” の代わりに “||” を使って,

public static boolean one_root(double a, double b, double c) {
  return !(two_roots(a, b, c) || no_roots(a, b, c));
}

としても同じ計算結果になる関数が定義できます.