Cで二次方程式を解の公式を使わずに解くプログラムを実装

More than 1 year has passed since last update.


中学数学網羅第二弾です


最初に

このプログラムは筆者が前に「解の公式」を使って二次方程式を解くプログラムを組んだら「解の公式がすごいだけ」と言われたのでプライド的なものを守るために組んだプログラムです。


コードを書く前に説明

二次方程式をこのように定義して


ax^2 + bx + c = 0

解の公式を使わずに解く方法は、

最初にx^2の係数を1にするために両辺をaで割ります


x^2 + (bx)/a + c/a = 0

そしてcを移項しします。


x^2 + (bx)/a = -c/a

さらに完全平方式を実行します


x^2 + bx/a + b^2/4a^2 = -c/a + b/4a

bx/4abx/a半分にして(分母を二倍)二乗した数です

これで完全平方式ができました


(x + b/2a)^2 = b^2-4ac/4a^2

だんだん近くなってきました

ここで両辺を平方根の形で表します


x + b/2a = ±√(b^2-4ac)/2a

これでbx/2aを移項して計算すれば


x = -b±√(b^2-4ac)/2a

となります。

自分も数式と説明が不慣れなのでうまく説明できたかどうかわかりませんがコードに入っていきましょう。


それではコードに移りましょう

勝手ながら"math.h"を使わない縛りもかけています。


変数の宣言

変数を宣言します。


main.c


double a, b, c; //係数の変数

double brackets_in_num; //完全平方式の時に使用する変数

double answer1, answer2; //解の変数

double num_get; //平方根の近似値を求める時に使う変数

double root_num = 0.0; //平方根の近似値の答えを格納する変数

double root_in_num = 0.0; //平方根の中身の変数

double tmp_a, tmp_b, tmp_c; //a,b,cをそのまま使わずに実行するために用意する変数

double add_num; //完全平方式の時に追加する数字を

int i; //ループ文のカウンタ


恐らく今回は分ける必要はなかったのですがif文などを実行する時に計算するa,b,cと分けといたほうがいいと思いましたので毎度お馴染みのリーダブルではない変数名にしています。(詳しくは下で解説)


入力を促す

入力を促して数字を読み込みます


main.c


printf("ax^2+bx+cのa,b,cの部分を入力してください。\n"); //入力を促す

printf("a = "); //aの入力を促す
scanf("%lf", &a); //aを読み込む

printf("b = "); //bの入力を促す
scanf("%lf", &b); //bを読み込む

printf("c = "); //cの入力を促す
scanf("%lf", &c); //cを読み込む



そのまま使用しないために計算用の変数に格納

さっきも説明した通り応用の時にxは〇〇以下なので二個目の解はこの問題に適していないなど出てくる場合があるので違う変数に格納します


main.c


tmp_a = a; //tmp_aにaを代入
tmp_b = b; //tmp_bにbを代入
tmp_c = c; //tmp_cにを代入



計算開始

本格的な計算に入っていきます

まず、両辺をx^2の係数で割ります


main.c


//両辺をaの係数で割る
tmp_a /= a;
tmp_b /= a;
tmp_c /= a;


そしてcを移項します


main.c


tmp_c *= -1; //cを移項



完全平方式を実行

()^2の形にしていきます。

まず()の中にbを半分にした数を代入


main.c


brackets_in_num = tmp_b / 2; //かっこの中に半分にしたbを入れる


追加する数を作る


main.c


add_num = brackets_in_num * brackets_in_num; //両辺に追加する変数にかっこの中の数を二乗した数を代入


右辺にも追加し、計算します


main.c


tmp_c += add_num; //右辺に追加して計算


一旦今の状況を数式で見て見ましょう。


(x + b/2a)^2 = b^2 - 4ac/4a^2

です。

なので、両辺の平方根を求めるためにtmp_cを違う変数に格納します


main.c


root_in_num = tmp_c; //右辺の平方根を求めるためにcを違う変数に格納



ルートの近似値を求める

このコードはまた違う記事に書こうと思いますが、先に掲載しておきます

ルートの近似値を求めるためのコードを書いていきます


main.c


num_get = 1.0; //ルートの近似値を求めるために使用する変数に1.0を代入
//ルートの近似値を求める
for (i = 1; i <= 7; i++) {
//ルートの近似値の二乗がルートの中の数字を超えるまでのループ
while (root_num * root_num <= root_in_num) {
root_num += num_get; //ループの条件に合うまで1を追加し続ける
}
root_num -= num_get; //ループを抜けた時は一つ大きいので1を引く
num_get /= 10.0; //足す数を10/1にする
//ループ終了(これを7回繰り返す)
}


解説としては、


(rootnum-1)^2 <= (rootnum)^2 <= (rootnum+1)^2

を繰り返している感じです。


方程式を解く

かっこの中の数字を移項してそれにroot_num(元はc)を足したり引いたりして解を求めます。


main.c


// かっこの中の数(元はb)を移項
brackets_in_num *= -1;

//二つの解を計算(ルートがプラスとマイナスなので引く解と、足す解が存在する)
answer1 = brackets_in_num + root_num; //足す解を計算
answer2 = brackets_in_num - root_num; //引く解を計算



答えを出力


main.c


printf("解 = %f , %f" ,answer1 , answer2);


これで、無事完成し、僕のプライドも守られました。


ソースコード


main.c


#include <stdio.h>

int main() {

double a, b, c; //係数の変数

double brackets_in_num; //完全平方式の時に使用する変数

double answer1, answer2; //解の変数

double num_get; //平方根の近似値を求める時に使う変数

double root_num = 0.0; //平方根の近似値の答えを格納する変数

double root_in_num = 0.0; //平方根の中身の変数

double tmp_a, tmp_b, tmp_c; //a,b,cをそのまま使わずに実行するために用意する変数

double add_num; //完全平方式の時に追加する数字を
int i; //ループ文のカウンタ
// double root_num;

printf("ax^2+bx+cのa,b,cの部分を入力してください。\n"); //入力を促す

printf("a = "); //aの入力を促す
scanf("%lf", &a); //aを読み込む

printf("b = "); //bの入力を促す
scanf("%lf", &b); //bを読み込む

printf("c = "); //cの入力を促す
scanf("%lf", &c); //cを読み込む

tmp_a = a; //tmp_aにaを代入
tmp_b = b; //tmp_bにbを代入
tmp_c = c; //tmp_cにを代入

//両辺をaの係数で割る
tmp_a /= a;
tmp_b /= a;
tmp_c /= a;

tmp_c *= -1; //cを移項

//完全平方式を実行
brackets_in_num = tmp_b / 2; //かっこの中に半分にしたbを入れる

add_num = brackets_in_num * brackets_in_num; //両辺に追加する変数にかっこの中の数を二乗した数を代入

tmp_c += add_num; //右辺に追加

root_in_num = tmp_c; //右辺の平方根を求めるためにcを違う変数に格納

//完全平方式終了

num_get = 1.0; //ルートの近似値を求めるために使用する変数に1.0を代入
//ルートの近似値を求める
for (i = 1; i <= 7; i++) {
//ルートの近似値の二乗がルートの中の数字を超えるまでのループ
while (root_num * root_num <= root_in_num) {
root_num += num_get; //ループの条件に合うまで1を追加し続ける
}
root_num -= num_get; //ループを抜けた時は一つ大きいので1を引く
num_get /= 10.0; //足す数を10/1にする
//ループ終了(これを7回繰り返す)
}
//ルートの近似値を求めるのは終了

// かっこの中の数(元はb)を移項
brackets_in_num *= -1;

//二つの解を計算(ルートがプラスとマイナスなので引く解と、足す解が存在する)
answer1 = brackets_in_num + root_num; //足す解を計算
answer2 = brackets_in_num - root_num; //引く解を計算

//答えを出力
printf("解 = %f , %f" ,answer1 , answer2);

}


ありがとうございました。