情報学部 菅沼ホーム 目次 索引

非線形方程式(二分法)

    1. A. C++
    2. B. Java
    3. C. JavaScript
    4. D. PHP
    5. E. Ruby
    6. F. Python
    7. G. C#
    8. H. VB

  プログラムは,f(x) = exp(x) - 3x = 0 の根を二分法で求めた例です.

  1. C++

    /*********************************/
    /* 二分法による exp(x)-3x=0 の根 */
    /*      coded by Y.Suganuma      */
    /*********************************/
    #include <stdio.h>
    #include <math.h>
    
    double bisection(double (*)(double), double, double, double,
                     double, int, int *);
    double snx(double);
    
    int main()
    {
    	double eps1, eps2, x, x1, x2;
    	int max, ind;
    /*
              データの設定
    */
    	eps1 = 1.0e-10;
    	eps2 = 1.0e-10;
    	max  = 100;
    	x1   = 0.0;
    	x2   = 1.0;
    /*
              実行と結果
    */
    	x = bisection(snx, x1, x2, eps1, eps2, max, &ind);
    
    	printf("   ind=%d  x=%f  f= %f\n", ind, x, snx(x));
    
    	return 0;
    }
    
    /****************/
    /* 関数値の計算 */
    /****************/
    double snx(double x)
    {
    	double y;
    	y = exp(x) - 3.0 * x;
    	return y;
    }
    
    /*********************************************************/
    /* 二分法による非線形方程式(f(x)=0)の解                  */
    /*      f : f(x)を計算する関数名                         */
    /*      x1,x2 : 初期値                                   */
    /*      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)       */
    /*      eps2 : 終了条件2(|f(x(k))|<eps2)           */
    /*      max : 最大試行回数                               */
    /*      ind : 実際の試行回数                             */
    /*            (負の時は解を得ることができなかった)     */
    /*      return : 解                                      */
    /*********************************************************/
    #include <math.h>
    
    double bisection(double(*f)(double), double x1, double x2,
                     double eps1, double eps2, int max, int *ind)
    {
    	double f0, f1, f2, x0 = 0.0;
    	int sw;
    
    	f1 = (*f)(x1);
    	f2 = (*f)(x2);
    
    	if (f1*f2 > 0.0)
    		*ind = -1;
    
    	else {
    		*ind = 0;
    		if (f1*f2 == 0.0)
    			x0 = (f1 == 0.0) ? x1 : x2;
    		else {
    			sw = 0;
    			while (sw == 0 && *ind >= 0) {
    				sw    = 1;
    				*ind += 1;
    				x0    = 0.5 * (x1 + x2);
    				f0    = (*f)(x0);
    
    				if (fabs(f0) > eps2) {
    					if (*ind <= max) {
    						if (fabs(x1-x2) > eps1 && fabs(x1-x2) > eps1*fabs(x2)) {
    							sw = 0;
    							if (f0*f1 < 0.0) {
    								x2 = x0;
    								f2 = f0;
    							}
    							else {
    								x1 = x0;
    								f1 = f0;
    							}
    						}
    					}
    					else
    						*ind = -1;
    				}
    			}
    		}
    	}
    
    	return x0;
    }
    			

  2. Java

    /*********************************/
    /* 二分法による exp(x)-3x=0 の根 */
    /*      coded by Y.Suganuma      */
    /*********************************/
    import java.io.*;
    
    public class Test {
    	public static void main(String args[]) throws IOException
    	{
    		double eps1, eps2, x, x1, x2;
    		int max, ind[] = new int [1];
    	/*
    	          データの設定
    	*/
    		eps1 = 1.0e-10;
    		eps2 = 1.0e-10;
    		max  = 100;
    		x1   = 0.0;
    		x2   = 1.0;
    	/*
    	          実行と結果
    	*/
    		Kansu kn = new Kansu();
    		x = kn.bisection(x1, x2, eps1, eps2, max, ind);
    
    		System.out.println("   ind=" + ind[0] + "  x=" + x + "  f=" + kn.snx(x));
    	}
    }
    
    /****************/
    /* 関数値の計算 */
    /****************/
    class Kansu extends Bisection
    {
    	double snx(double x)
    	{
    		double y = Math.exp(x) - 3.0 * x;
    		return y;
    	}
    }
    
    abstract class Bisection
    {
    	/*********************************************************/
    	/* 二分法による非線形方程式(f(x)=0)の解                  */
    	/*      x1,x2 : 初期値                                   */
    	/*      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)       */
    	/*      eps2 : 終了条件2(|f(x(k))|<eps2)           */
    	/*      max : 最大試行回数                               */
    	/*      ind : 実際の試行回数                             */
    	/*            (負の時は解を得ることができなかった)     */
    	/*      return : 解                                      */
    	/*********************************************************/
    
    	abstract double snx(double x);   // 定義しておく必要あり
    
    	double bisection(double x1, double x2, double eps1, double eps2, int max, int ind[])
    	{
    		double f0, f1, f2, x0 = 0.0;
    		int sw;
    
    		f1 = snx(x1);
    		f2 = snx(x2);
    
    		if (f1*f2 > 0.0)
    			ind[0] = -1;
    
    		else {
    			ind[0] = 0;
    			if (f1*f2 == 0.0)
    				x0 = (f1 == 0.0) ? x1 : x2;
    			else {
    				sw = 0;
    				while (sw == 0 && ind[0] >= 0) {
    					sw      = 1;
    					ind[0] += 1;
    					x0      = 0.5 * (x1 + x2);
    					f0      = snx(x0);
    					if (Math.abs(f0) > eps2) {
    						if (ind[0] <= max) {
    							if (Math.abs(x1-x2) > eps1 && Math.abs(x1-x2) > eps1*Math.abs(x2)) {
    								sw = 0;
    								if (f0*f1 < 0.0) {
    									x2 = x0;
    									f2 = f0;
    								}
    								else {
    									x1 = x0;
    									f1 = f0;
    								}
    							}
    						}
    						else
    							ind[0] = -1;
    					}
    				}
    			}
    		}
    
    		return x0;
    	}
    }
    			

  3. JavaScript

      ここをクリックすると,JavaScript の仕様に適合した形で解を求めたい式を入力することによって,任意の非線形方程式の解を画面上で求めることができます.
    <!DOCTYPE HTML>
    
    <HTML>
    
    <HEAD>
    
    	<TITLE>非線形方程式(二分法)</TITLE>
    	<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
    	<SCRIPT TYPE="text/javascript">
    		str = "";
    		ind = 0;   // 実際の試行回数(負の時は解を得ることができなかった)
    		function main()
    		{
    			str = document.getElementById("func").value + ";";
    					// データの設定
    			let eps1 = 1.0e-10;
    			let eps2 = 1.0e-10;
    			let max  = parseInt(document.getElementById("max").value);
    			let x1   = parseFloat(document.getElementById("x1").value);
    			let x2   = parseFloat(document.getElementById("x2").value);
    			ind      = 0;
    					// 実行
    			let x = bisection(x1, x2, eps1, eps2, max, snx);
    					// 結果
    			if (ind < 0)
    				document.getElementById("res").value = "解を求めることができませんでした!";
    			else {
    				let c = 100000;
    				let s1 = Math.round(x * c) / c;
    				document.getElementById("res").value = " x = " + s1 + ", 収束回数:" + ind;
    			}
    		}
    
    		/****************/
    		/* 関数値の計算 */
    		/****************/
    		function snx(x)
    		{
    			let y = eval(str);
    			return y;
    		}
    
    		/**************************************************/
    		/* 二分法による非線形方程式(f(x)=0)の解           */
    		/*      x1,x2 : 初期値                            */
    		/*      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)*/
    		/*      eps2 : 終了条件2(|f(x(k))|<eps2)    */
    		/*      max : 最大試行回数                        */
    		/*      fn : 関数値を計算する関数                 */
    		/*      return : 解                               */
    		/**************************************************/
    		function bisection(x1, x2, eps1, eps2, max, fn)
    		{
    			let sw, f0, x0 = 0.0;
    
    			let f1 = fn(x1);
    			let f2 = fn(x2);
    
    			if (f1*f2 > 0.0)
    				ind = -1;
    
    			else {
    				ind = 0;
    				if (f1*f2 == 0.0)
    					x0 = (f1 == 0.0) ? x1 : x2;
    				else {
    					sw = 0;
    					while (sw == 0 && ind >= 0) {
    						sw   = 1;
    						ind += 1;
    						x0   = 0.5 * (x1 + x2);
    						f0   = fn(x0);
    
    						if (Math.abs(f0) > eps2) {
    							if (ind <= max) {
    								if (Math.abs(x1-x2) > eps1 && Math.abs(x1-x2) > eps1*Math.abs(x2)) {
    									sw = 0;
    									if (f0*f1 < 0.0) {
    										x2 = x0;
    										f2 = f0;
    									}
    									else {
    										x1 = x0;
    										f1 = f0;
    									}
    								}
    							}
    							else
    								ind = -1;
    						}
    					}
    				}
    			}
    
    			return x0;
    		}
    	</SCRIPT>
    
    </HEAD>
    
    <BODY STYLE="font-size: 130%; background-color: #eeffee;">
    
    	<H2 STYLE="text-align:center"><B>非線形方程式(二分法)</B></H2>
    
    	<DL>
    		<DT>  テキストフィールドには,例として,以下に示すような非線形方程式の解を求める場合に対する値が設定されています.他の問題を実行する場合は,それらを適切に修正してください.なお,式は,JavaScript の仕様に適合した形式で記述してあることに注意してください.
    		<P STYLE="text-align:center"><IMG SRC="bisec.gif"></P>
    	</DL>
    
    	<DIV STYLE="text-align:center">
    		初期値:<INPUT ID="x1" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="0">,
    				<INPUT ID="x2" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="1"> 
    		最大繰り返し回数:<INPUT ID="max" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="100"><BR><BR>
    		式:<INPUT ID="func" STYLE="font-size: 100%" TYPE="text" SIZE="50" VALUE="Math.exp(x) - 3.0 * x">= 0  
    		<BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">実行</BUTTON><BR><BR>
    		結果:<INPUT ID="res" STYLE="font-size: 100%" TYPE="text" SIZE="30">
    	</DIV>
    
    </BODY>
    
    </HTML>
    			

  4. PHP

    <?php
    
    /*
              データの設定
    */
    	$eps1 = 1.0e-10;
    	$eps2 = 1.0e-10;
    	$max  = 100;
    	$x1   = 0.0;
    	$x2   = 1.0;
    /*
              実行と結果
    */
    	$x = bisection("snx", $x1, $x2, $eps1, $eps2, $max, $ind);
    
    	printf("   ind=%d  x=%f  f= %f\n", $ind, $x, snx($x));
    
    /*********************************/
    /* 二分法による exp(x)-3x=0 の根 */
    /*      coded by Y.Suganuma      */
    /*********************************/
    
    /****************/
    /* 関数値の計算 */
    /****************/
    function snx($x)
    {
    	return exp($x) - 3.0 * $x;
    }
    
    /*********************************************************/
    /* 二分法による非線形方程式(f(x)=0)の解                  */
    /*      fn : f(x)を計算する関数名                        */
    /*      x1,x2 : 初期値                                   */
    /*      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)       */
    /*      eps2 : 終了条件2(|f(x(k))|<eps2)           */
    /*      max : 最大試行回数                               */
    /*      ind : 実際の試行回数                             */
    /*            (負の時は解を得ることができなかった)     */
    /*      return : 解                                      */
    /*********************************************************/
    function bisection($fn, $x1, $x2, $eps1, $eps2, $max, &$ind)
    {
    	$x0 = 0.0;
    	$f1 = $fn($x1);
    	$f2 = $fn($x2);
    
    	if ($f1*$f2 > 0.0)
    		$ind = -1;
    
    	else {
    		$ind = 0;
    		if ($f1*$f2 == 0.0)
    			$x0 = ($f1 == 0.0) ? $x1 : $x2;
    		else {
    			$sw = 0;
    			while ($sw == 0 && $ind >= 0) {
    				$sw    = 1;
    				$ind += 1;
    				$x0    = 0.5 * ($x1 + $x2);
    				$f0    = $fn($x0);
    
    				if (abs($f0) > $eps2) {
    					if ($ind <= $max) {
    						if (abs($x1-$x2) > $eps1 && abs($x1-$x2) > $eps1*abs($x2)) {
    							$sw = 0;
    							if ($f0*$f1 < 0.0) {
    								$x2 = $x0;
    								$f2 = $f0;
    							}
    							else {
    								$x1 = $x0;
    								$f1 = $f0;
    							}
    						}
    					}
    					else
    						$ind = -1;
    				}
    			}
    		}
    	}
    
    	return $x0;
    }
    
    ?>
    			

  5. Ruby

    ############################################
    # 二分法による exp(x)-3x=0 の根
    #      coded by Y.Suganuma
    ############################################
    
    ############################################
    # 二分法による非線形方程式(f(x)=0)の解
    #      x1,x2 : 初期値
    #      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)
    #      eps2 : 終了条件2(|f(x(k))|<eps2)
    #      max : 最大試行回数
    #      ind : 実際の試行回数
    #            (負の時は解を得ることができなかった)
    #      fn : f(x)を計算する関数名
    #      return : 解
    #      coded by Y.Suganuma
    ############################################
    
    def bisection(x1, x2, eps1, eps2, max, ind, &fn)
    
    	x0 = 0.0
    	f1 = fn.call(x1)
    	f2 = fn.call(x2)
    
    	if f1*f2 > 0.0
    		ind[0] = -1
    
    	else
    		ind[0] = 0
    		if f1*f2 == 0.0
    			if f1 == 0.0
    				x0 = x1
    			else
    				x0 = x2
    			end
    		else
    			sw = 0
    			while sw == 0 && ind[0] >= 0
    				sw      = 1
    				ind[0] += 1
    				x0     = 0.5 * (x1 + x2)
    				f0     = fn.call(x0)
    
    				if f0.abs() > eps2
    					if ind[0] <= max
    						if (x1-x2).abs() > eps1 && (x1-x2).abs() > eps1*x2.abs()
    							sw = 0
    							if f0*f1 < 0.0
    								x2 = x0
    								f2 = f0
    							else
    								x1 = x0
    								f1 = f0
    							end
    						end
    					else
    						ind[0] = -1
    					end
    				end
    			end
    		end
    	end
    
    	return x0
    end
    
    ################
    # 関数値の計算 #
    ################
    snx = Proc.new { |x|
    	Math.exp(x) - 3.0 * x
    }
    
    			# データの設定
    eps1 = 1.0e-10
    eps2 = 1.0e-10
    max  = 100
    x1   = 0.0
    x2   = 1.0
    ind  = [0]
    			# 実行と結果
    x = bisection(x1, x2, eps1, eps2, max, ind, &snx)
    
    print("   ind=", ind[0], "  x=", x, "  f= ", snx.call(x), "\n")
    			

  6. Python

    # -*- coding: UTF-8 -*-
    import numpy as np
    from math import *
    
    ############################################
    # 二分法による非線形方程式(f(x)=0)の解
    #      fn : f(x)を計算する関数名
    #      x1,x2 : 初期値
    #      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)
    #      eps2 : 終了条件2(|f(x(k))|<eps2)
    #      max : 最大試行回数
    #      ind : 実際の試行回数
    #            (負の時は解を得ることができなかった)
    #      return : 解
    #      coded by Y.Suganuma
    ############################################
    
    def bisection(fn, x1, x2, eps1, eps2, max, ind) :
    
    	x0 = 0.0
    	f1 = fn(x1)
    	f2 = fn(x2)
    
    	if f1*f2 > 0.0 :
    		ind[0] = -1
    
    	else :
    		ind[0] = 0
    		if f1*f2 == 0.0 :
    			if f1 == 0.0 :
    				x0 = x1
    			else :
    				x0 = x2
    		else :
    			sw = 0
    			while sw == 0 and ind[0] >= 0 :
    				sw      = 1
    				ind[0] += 1
    				x0     = 0.5 * (x1 + x2)
    				f0     = fn(x0)
    
    				if abs(f0) > eps2 :
    					if ind[0] <= max :
    						if abs(x1-x2) > eps1 and abs(x1-x2) > eps1*abs(x2) :
    							sw = 0
    							if f0*f1 < 0.0 :
    								x2 = x0
    								f2 = f0
    							else :
    								x1 = x0
    								f1 = f0
    					else :
    						ind[0] = -1
    
    	return x0
    
    ################
    # 関数値の計算 #
    ################
    def snx(x) :
    	return exp(x) - 3.0 * x
    
    ############################################
    # 二分法による exp(x)-3x=0 の根
    #      coded by Y.Suganuma
    ############################################
    
    			# データの設定
    eps1 = 1.0e-10
    eps2 = 1.0e-10
    max  = 100
    x1   = 0.0
    x2   = 1.0
    ind  = [0]
    			# 実行と結果
    x = bisection(snx, x1, x2, eps1, eps2, max, ind)
    
    print("   ind=" + str(ind[0]) + "  x=" + str(x) + "  f= " + str(snx(x)))
    			

  7. C#

    /*********************************/
    /* 二分法による exp(x)-3x=0 の根 */
    /*      coded by Y.Suganuma      */
    /*********************************/
    using System;
    
    class Program
    {
    	static void Main()
    	{
    		Test1 ts = new Test1();
    	}
    }
    
    class Test1
    {
    	public Test1()
    	{
    	/*
    	          データの設定
    	*/
    		double eps1 = 1.0e-10;
    		double eps2 = 1.0e-10;
    		double x1   = 0.0;
    		double x2   = 1.0;
    		int max     = 100;
    		int ind     = 0;
    	/*
    	          実行と結果
    	*/
    		double x = bisection(x1, x2, eps1, eps2, max, ref ind, snx);
    
    		Console.WriteLine("   ind=" + ind + "  x=" + x + "  f=" + snx(x));
    	}
    
    	/****************/
    	/* 関数値の計算 */
    	/****************/
    	double snx(double x)
    	{
    		return Math.Exp(x) - 3.0 * x;
    	}
    
    	/*********************************************************/
    	/* 二分法による非線形方程式(f(x)=0)の解                  */
    	/*      x1,x2 : 初期値                                   */
    	/*      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)       */
    	/*      eps2 : 終了条件2(|f(x(k))|<eps2)           */
    	/*      max : 最大試行回数                               */
    	/*      ind : 実際の試行回数                             */
    	/*            (負の時は解を得ることができなかった)     */
    	/*      fn : 関数値を計算する関数                        */
    	/*      return : 解                                      */
    	/*********************************************************/
    	double bisection(double x1, double x2, double eps1, double eps2, int max,
    	                 ref int ind, Func<double, double> fn)
    	{
    		double f1 = fn(x1);
    		double f2 = fn(x2);
    		double x0 = 0.0;
    
    		if (f1*f2 > 0.0)
    			ind = -1;
    
    		else {
    			ind = 0;
    			if (f1*f2 == 0.0)
    				x0 = (f1 == 0.0) ? x1 : x2;
    			else {
    				int sw = 0;
    				while (sw == 0 && ind >= 0) {
    					sw        = 1;
    					ind      += 1;
    					x0        = 0.5 * (x1 + x2);
    					double f0 = fn(x0);
    					if (Math.Abs(f0) > eps2) {
    						if (ind <= max) {
    							if (Math.Abs(x1-x2) > eps1 && Math.Abs(x1-x2) > eps1*Math.Abs(x2)) {
    								sw = 0;
    								if (f0*f1 < 0.0) {
    									x2 = x0;
    									f2 = f0;
    								}
    								else {
    									x1 = x0;
    									f1 = f0;
    								}
    							}
    						}
    						else
    							ind = -1;
    					}
    				}
    			}
    		}
    
    		return x0;
    	}
    }
    			

  8. VB

    '''''''''''''''''''''''''''''''''
    ' 二分法による exp(x)-3x=0 の根 '
    '      coded by Y.Suganuma      '
    '''''''''''''''''''''''''''''''''
    Module Test
    	Sub Main()
    				'
    				' データの設定
    				'
    		Dim eps1 As Double = 1.0e-10
    		Dim eps2 As Double = 1.0e-10
    		Dim x1 As Double   = 0.0
    		Dim x2 As Double   = 1.0
    		Dim max As Integer = 100
    		Dim ind As Integer = 0
    				'
    				' 実行と結果
    				'
    		Dim snx = Function(v) As Double   ' 関数値の計算(ラムダ式)
    	                  Return Math.Exp(v) - 3.0 * v
    	              End Function
    
    		Dim x As Double = bisection(x1, x2, eps1, eps2, max, ind, snx)
    
    		Console.WriteLine("   ind=" & ind & " x=" & x & "  f=" & snx(x))
    
    	End Sub
    
    	'''''''''''''''''''''''''''''''''''''''''''''''''''''
    	' 二分法による非線形方程式(f(x)=0)の解              '
    	'      x1,x2 : 初期値                               '
    	'      eps1 : 終了条件1(|x(k+1)-x(k)|<eps1)   '
    	'      eps2 : 終了条件2(|f(x(k))|<eps2)       '
    	'      max : 最大試行回数                           '
    	'      ind : 実際の試行回数                         '
    	'            (負の時は解を得ることができなかった) '
    	'      fn : 関数値を計算する関数                    '
    	'      return : 解                                  '
    	'''''''''''''''''''''''''''''''''''''''''''''''''''''
    	Function bisection(x1 As Double, x2 As Double, eps1 As Double, eps2 As Double,
    	                   max As Integer, ByRef ind As Integer,
    	                   fn As Func(Of Double, Double))
    
    		Dim f1 As Double = fn(x1)
    		Dim f2 As Double = fn(x2)
    		Dim x0 As Double = 0.0
    
    		If f1*f2 > 0.0
    			ind = -1
    
    		Else
    			ind = 0
    			If f1*f2 = 0.0
    				If f1 = 0.0
    					x0 = x1
    				Else
    					x0 = x2
    				End If
    			Else
    				Dim sw As Integer = 0
    				Do While sw = 0 and ind >= 0
    					sw   = 1
    					ind += 1
    					x0   = 0.5 * (x1 + x2)
    					Dim f0 As Double = fn(x0)
    					If Math.Abs(f0) > eps2
    						If ind <= max
    							If Math.Abs(x1-x2) > eps1 and Math.Abs(x1-x2) > eps1*Math.Abs(x2)
    								sw = 0
    								If f0*f1 < 0.0
    									x2 = x0
    									f2 = f0
    								Else
    									x1 = x0
    									f1 = f0
    								End If
    							End If
    						Else
    							ind = -1
    						End If
    					End If
    				Loop
    			End If
    		End If
    
    		Return x0
    
    	End Function
    
    End Module
    			

情報学部 菅沼ホーム 目次 索引