Jasmine Tea で二次方程式の解を求めてみる

これは [Jasmine Tea アドベントカレンダー 2023](https://qiita.com/advent-calendar/2023/jasminetea) の  12 日目の記事です。

こんにちは、[Jasmine Tea](https://jasminetea.app/) の開発に参加している石川です。この記事では、二次方程式の実数解[^1]を求める関数を作ってみます。Jasmine Tea の関数については [11 日目](https://qiita.com/mntsh/items/f74a6b4be456b73a1495)の記事を参照してください。

[^1]: 以降、実数解を単に「解」と言います

二次方程式 $ a x^2 + b x + c = 0 \quad (a \neq 0) $ の解は以下のように求まります。(現在の学習指導要領では中学校 ３ 年で習うことになっていると思います。)

$$
x = \frac{-b \pm \sqrt{ b^2 - 4ac } }{2a}
$$

これを Jasmine Tea に計算させてみましょう。この記事では、$a$ と $b$ と $c$ の ３ つの値を与えると解を返す関数を作ることで実現します。

## 解の求め方の概要

まず、$ a x^2 + b x + c = 0 $ が二次方程式であるためには $a \neq 0$ の条件が重要です。そのため、関数の最初では $a = 0$ の場合にエラーを出力するようにしましょう。

次に、二次方程式解の数は、 $b^2 - 4ac$ の値によって変わります。

- $b^2 - 4ac < 0$ の場合: 解なし
- $b^2 - 4ac = 0$ の場合: 解は 1 つ
- $b^2 - 4ac > 0$ の場合: 解は 2 つ

このように、解が 0, 1, 2 つのケースが有るため、関数の戻り値は配列を使うとよさそうです。

この考察をもとに、プログラムを書いてみましょう。今回は次のステップで書いてみますが、これはあくまでも例です。実装をする順番は自由なので、ステップを入れ替えても問題ありません。

1. 関数の骨組みを作る
2. 条件分岐を作る
3. 返す値を作る
4. エラー処理を作る

## 1. 関数の骨組みを作る

関数の骨組みは `function` と `end function` で作ります。このとき、次の 3 つの要素を決める必要があります。

- 関数の名前
- 与える値 (引数)
- 返す値 (戻り値) の種類

ここでは、関数の名前は `solve_quadratic` とします。与える値は `a`, `b`, `c` の数値 3 つで、返す値の種類は配列にします。そうすると、関数の骨組みは以下のようになります。

```
function solve_quadratic@(a, b, c)
end function
```

## 2. 条件分岐を作る

二次方程式では、 $b^2 - 4ac$ の値によって解の個数が変わります。プログラムでこれを表現するには、条件分岐 `if` を使うとよさそうです。まずは $b^2 - 4ac$ を計算しましょう。計算結果は `pm_term_squared` (プラスマイナス項の 2 乗) という変数に代入してみます。$b$ の 2 乗 ($b^2$) を計算するには、`pow` 関数が使えます。

```
function solve_quadratic@(a, b, c)
  pm_term_squared = pow(b, 2) - 4 * a * c
end function
```

あとは、「`pm_term_squared` が 0 より小さい」、「0 と等しい」、「0 より大きい」の 3 つの条件で分岐すればよさそうです。プログラムにすると以下のようになります。

```
function solve_quadratic@(a, b, c)
  pm_term_squared = pow(b, 2) - 4 * a * c
  if pm_term_squared < 0 then
    
  else if pm_term_squared = 0 then
    
  else
    
  end if
end function
```

最後の「0 より大きい」の部分では `else if` と書かなくとも、`else` で十分です。

## 3. 返す値を作る

繰り返しになりますが、二次方程式解の数は、 $b^2 - 4ac$ の値によって変わります。この解を配列として返すには、以下のようにすればよさそうです。

- $b^2 - 4ac < 0$ の場合: 空配列 `[]` を返す
- $b^2 - 4ac = 0$ の場合: $-\frac{b}{2a}$ を要素に持つ配列を返す
- $b^2 - 4ac > 0$ の場合: $\frac{-b - \sqrt{b^2 - 4ac}}{2a}$ と $\frac{-b + \sqrt{b^2 - 4ac}}{2a}$ を要素に持つ配列を返す

これをプログラムにしてみましょう。なお、正の平方根は `sqr` 関数を使うことで計算することができます。


```
function solve_quadratic@(a, b, c)
  pm_term_squared = pow(b, 2) - 4 * a * c
  if pm_term_squared < 0 then
    return []
  else if pm_term_squared = 0 then
    return [-b / 2 * a]
  else
    pm_term = sqr(pm_term_squared)
    return [(-b - pm_term) / 2 * a, (-b + pm_term) / 2 * a]
  end if
end function
```

## 4. エラー処理を作る

先程のコードでほぼ完成なのですが、まだ $a \neq 0$ の条件を取り扱っていません。$a = 0$ の場合は二次方程式ではなくなるため、エラーとして処理しましょう。今回は、説明を `print` で出力し、`stop` で実行を中断するという動作にしてみます。

```
function solve_quadratic@(a, b, c)
  if a = 0 then
    print "aの値は0以外を指定してください"
    stop
  end if
  
  pm_term_squared = pow(b, 2) - 4 * a * c
  if pm_term_squared < 0 then
    return []
  else if pm_term_squared = 0 then
    return [-b / 2 * a]
  else
    pm_term = sqr(pm_term_squared)
    return [(-b - pm_term) / 2 * a, (-b + pm_term) / 2 * a]
  end if
end function
```

## 使ってみる

この関数 `solve_quadratic@(a, b, c)` を使って、２次方程式の解を求めてみます。

例えば `print solve_quadratic@(1, 2, 1)` を実行すると、`[-1]` が実行画面に出力されるはずです。
![output](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635491/5a070ff5-b6d3-2c12-1b7a-e1dfb92ca3bf.png)

ここで作成したプログラムは[ここ](https://jasminetea.app/studio/projects/yrogqc5DY579MRs4GxfF)で利用できますので、参考にしてみてください。