4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-09-07

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

##コードを書く前に説明
二次方程式をこのように定義して


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);
    
}

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

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?