32.9 条件分岐

2次方程式“ax2+bx+c=0”に対して解の個数を求める関数を作ってみましょう.ここまでで見てきたように,解を0, 1, 2個持つ場合の条件をそれぞれ式として書くことができていますので,あとは

  • 「解を1つも持たない」条件が成り立つならば“0”,
  • 「解を1つ持つ」条件が成り立つならば“1”,
  • 「解を2つ持つ」条件が成り立つならば“2”,

となるような式を作ればよいわけです.
このように,条件の真偽によって異なる処理をさせることを一般に条件分岐と言います.

条件分岐の方法

OCamlで条件分岐をしたい時は,

if 条件 then 式1 else 式2

のように書きます.この時,「条件」が成り立つ,つまり真偽値を計算して“true”だったら「式1」が計算され,“false”だったら「式2」が計算されます.そしてその計算結果が全体の結果になります.
簡単な利用例を少し見てみましょう.

if 1.3 >= 5.2 then 1.3 else 5.2;;return2
- : float = 5.2
let max(a, b) = if a >= b then a else b;;return2
val max : 'a * 'a -> 'a = <fun>
max(1.3, 5.2);;return2
- : float = 5.2
if 6 mod 2 then true else false;;return2
Error: This expression has type int but an expression was expected of type bool (* 条件の部分は計算すると真偽値になるようにする必要がある *)
let try_sqrt(x) = if x >= 0.0 then sqrt(x) else false;;return2
Error: This expression has type bool but an expression was expected of type float (* 分岐した先の2つの式は値の種類が一致する必要がある *)

条件分岐ができるようになると,だいぶ計算できるものが増えます.

条件分岐の利用

条件分岐を使って,解の個数を求める関数“number_of_roots”は次のように書くことができます.

let number_of_roots(a, b, c) = if no_roots(a, b, c) then 0 else (if one_root(a, b, c) then 1 else 2);;return2
val number_of_roots : float * float * float -> int = <fun>

少し複雑な式ですが,分解して考えればそれほど難しくありません.前から順に見てゆくと,

  • “if no_roots(a, b, c) then 0 else (…)”は「解を1つも持たないならば“0”,そうでなければ“(…)”」を表わします.
  • そして“(…)”の部分の“if one_root(a, b, c) then 1 else 2”は「解を1つ持つならば“1”,そうでなければ“2”」を表わしています.

この2つを合わせると,次のようになります.

  • 「解を1つも持たない」ならば“0”.
  • 「そうでない(解を1つか2つ持つ)」ならば,「『解を1つ持つ』ならば“1”,『そうでない』ならば“2”」.

つまり,

  • 「解を1つも持たない」ならば“0”.
  • (解を1つか2つ持つときに)「解を1つ持つ」ならば“1”.
  • (解を1つか2つ持つときに)「解を1つ持たない」ならば“2”.

であるので,結局

  • 「解を1つも持たない」ならば“0”.
  • 「解を1つ持つ」ならば“1”.
  • 「解を2つ持つ」ならば“1”.

ということになります.
実際に計算させて正しく解の個数を求めているか調べてみましょう.

number_of_roots(1.0, -5.0, 6.0);;return2
- : int = 2
number_of_roots(1.0, 2.0, 1.0);;return2
- : int = 1
number_of_roots(1.0, 2.0, 2.0);;return2
- : int = 0

良さそうですね.
ここまでに出てきた,2次方程式の解の公式と解の個数を調べる関数の定義をまとめると次のようになります.

(* quadratic.ml: 2次方程式 ax^2 + bx + c = 0 *)
(* 自乗 *)
let square(x) = x *. x
(* 判別式 *)
let discriminant(a, b, c) = square(b) -. 4.0 *. a *. c
(* 解の公式 *)
let quadratic1(a, b, c) = (-. b +. sqrt(discriminant(a,b,c))) /. (2.0 *. a)
let quadratic2(a, b, c) = (-. b -. sqrt(discriminant(a,b,c))) /. (2.0 *. a)
(* 十分小さい数を用意 *)
let eps = 0.000001
(* 二根を持つ,解なし,重根を持つ条件 *)
let two_roots(a, b, c) = discriminant(a, b, c) > eps
let no_roots(a, b, c) = discriminant(a, b, c) < -. eps
let one_root(a, b, c) = not(two_roots(a, b, c)) && not(no_roots(a, b, c))
(* 解の個数 *)
let number_of_roots(a, b, c) =
  if no_roots(a, b, c) then 0 else (if one_root(a, b, c) then 1 else 2)