| 情報学部 | 菅沼ホーム | 目次 | 索引 |
/*********************************************/
/* 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値 */
/* coded by Y.Suganuma */
/*********************************************/
#include <stdio.h>
double snx(double);
double gold(double, double, double, double *, int *, int, double (*)(double));
int main()
{
double a, b, eps, val, x;
int ind, max;
a = -2.0;
b = -1.0;
eps = 1.0e-10;
max = 100;
x = gold(a, b, eps, &val, &ind, max, snx);
printf("x %f val %f ind %d\n", x, val, ind);
return 0;
}
/****************/
/* 関数値の計算 */
/****************/
double snx(double x)
{
double f;
f = x * x * x * x + 3.0 * x * x * x + 2.0 * x * x + 1.0;
return f;
}
/******************************************/
/* 黄金分割法(関数の最小値) */
/* a,b : 初期区間 a < b */
/* eps : 許容誤差 */
/* val : 間数値 */
/* ind : 計算状況 */
/* >= 0 : 正常終了(収束回数) */
/* = -1 : 収束せず */
/* max : 最大試行回数 */
/* fun : 関数値を計算する関数の名前 */
/* return : 結果 */
/******************************************/
#include <math.h>
double gold(double a, double b, double eps, double *val, int *ind, int max, double (*fun)(double))
{
double f1, f2, fa, fb, tau, x = 0.0, x1, x2;
int count;
tau = (sqrt(5.0) - 1.0) / 2.0;
count = 0;
*ind = -1;
x1 = b - tau * (b - a);
x2 = a + tau * (b - a);
f1 = fun(x1);
f2 = fun(x2);
while (count < max && *ind < 0) {
count += 1;
if (f2 > f1) {
if (fabs(b-a) < eps && fabs(b-a) < eps*fabs(b)) {
*ind = 0;
x = x1;
*val = f1;
}
else {
b = x2;
x2 = x1;
x1 = a + (1.0 - tau) * (b - a);
f2 = f1;
f1 = fun(x1);
}
}
else {
if (fabs(b-a) < eps && fabs(b-a) < eps*fabs(b)) {
*ind = 0;
x = x2;
*val = f2;
f1 = f2;
}
else {
a = x1;
x1 = x2;
x2 = b - (1.0 - tau) * (b - a);
f1 = f2;
f2 = fun(x2);
}
}
}
if (*ind == 0) {
*ind = count;
fa = fun(a);
fb = fun(b);
if (fb < fa) {
a = b;
fa = fb;
}
if (fa < f1) {
x = a;
*val = fa;
}
}
return x;
}
/*********************************************/
/* 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値 */
/* coded by Y.Suganuma */
/*********************************************/
import java.io.*;
public class Test {
public static void main(String args[]) throws IOException
{
double a, b, eps, x, val[] = new double [1];
int max, ind[] = new int [1];
a = -2.0;
b = -1.0;
eps = 1.0e-10;
max = 100;
Kansu kn = new Kansu();
x = kn.gold(a, b, eps, val, ind, max);
System.out.println("x " + x + " val " + val[0] + " ind " + ind[0]);
}
}
/****************/
/* 関数値の計算 */
/****************/
class Kansu extends Gold
{
double snx(double x)
{
double y = x * x * x * x + 3.0 * x * x * x + 2.0 * x * x + 1.0;
return y;
}
}
abstract class Gold
{
/************************************************/
/* 黄金分割法(関数の最小値) */
/* a,b : 初期区間 a < b */
/* eps : 許容誤差 */
/* val : 間数値 */
/* ind : 計算状況 */
/* >= 0 : 正常終了(収束回数) */
/* = -1 : 収束せず */
/* max : 最大試行回数 */
/* return : 結果 */
/************************************************/
abstract double snx(double x);
double gold(double a, double b, double eps, double val[], int ind[], int max)
{
double f1, f2, fa, fb, tau, x = 0.0, x1, x2;
int count;
tau = (Math.sqrt(5.0) - 1.0) / 2.0;
count = 0;
ind[0] = -1;
x1 = b - tau * (b - a);
x2 = a + tau * (b - a);
f1 = snx(x1);
f2 = snx(x2);
while (count < max && ind[0] < 0) {
count += 1;
if (f2 > f1) {
if (Math.abs(b-a) < eps && Math.abs(b-a) < eps*Math.abs(b)) {
ind[0] = 0;
x = x1;
val[0] = f1;
}
else {
b = x2;
x2 = x1;
x1 = a + (1.0 - tau) * (b - a);
f2 = f1;
f1 = snx(x1);
}
}
else {
if (Math.abs(b-a) < eps && Math.abs(b-a) < eps*Math.abs(b)) {
ind[0] = 0;
x = x2;
val[0] = f2;
f1 = f2;
}
else {
a = x1;
x1 = x2;
x2 = b - (1.0 - tau) * (b - a);
f1 = f2;
f2 = snx(x2);
}
}
}
if (ind[0] == 0) {
ind[0] = count;
fa = snx(a);
fb = snx(b);
if (fb < fa) {
a = b;
fa = fb;
}
if (fa < f1) {
x = a;
val[0] = fa;
}
}
return x;
}
}
<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE>最適化(黄金分割法)</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<SCRIPT TYPE="text/javascript">
str = "";
function main()
{
str = document.getElementById("func").value + ";";
// データの設定
let a = parseFloat(document.getElementById("a").value);
let b = parseFloat(document.getElementById("b").value);
let max = parseInt(document.getElementById("max").value);
let eps = 1.0e-10;
let val = new Array();
let ind = new Array();
// 実行
let x = gold(a, b, eps, val, ind, max, snx);
// 結果
if (ind < 0)
document.getElementById("res").value = "解を求めることができませんでした!";
else {
let c = 100000;
let s1 = Math.round(x * c) / c;
let s2 = Math.round(val[0] * c) / c;
document.getElementById("res").value = " x = " + s1 + ",f(x) = " + s2 + ",ind = " + ind[0];
}
}
/****************/
/* 関数値の計算 */
/****************/
function snx(x)
{
let y = eval(str);
return y;
}
/*******************************************/
/* 黄金分割法(関数の最小値) */
/* a,b : 初期区間 a < b */
/* eps : 許容誤差 */
/* val : 間数値 */
/* ind : 計算状況 */
/* >= 0 : 正常終了(収束回数) */
/* = -1 : 収束せず */
/* max : 最大試行回数 */
/* return : 結果 */
/*******************************************/
function gold(a, b, eps, val, ind, max)
{
let tau = (Math.sqrt(5.0) - 1.0) / 2.0;
let count = 0;
ind[0] = -1;
let x = 0.0;
let x1 = b - tau * (b - a);
let x2 = a + tau * (b - a);
let f1 = snx(x1);
let f2 = snx(x2);
while (count < max && ind[0] < 0) {
count += 1;
if (f2 > f1) {
if (Math.abs(b-a) < eps && Math.abs(b-a) < eps*Math.abs(b)) {
ind[0] = 0;
x = x1;
val[0] = f1;
}
else {
b = x2;
x2 = x1;
x1 = a + (1.0 - tau) * (b - a);
f2 = f1;
f1 = snx(x1);
}
}
else {
if (Math.abs(b-a) < eps && Math.abs(b-a) < eps*Math.abs(b)) {
ind[0] = 0;
x = x2;
val[0] = f2;
f1 = f2;
}
else {
a = x1;
x1 = x2;
x2 = b - (1.0 - tau) * (b - a);
f1 = f2;
f2 = snx(x2);
}
}
}
if (ind[0] == 0) {
ind[0] = count;
let fa = snx(a);
let fb = snx(b);
if (fb < fa) {
a = b;
fa = fb;
}
if (fa < f1) {
x = a;
val[0] = fa;
}
}
return x;
}
</SCRIPT>
</HEAD>
<BODY STYLE="font-size: 130%; background-color: #eeffee;">
<H2 STYLE="text-align:center"><B>最適化(黄金分割法)</B></H2>
<DL>
<DT> テキストフィールドには,例として,以下に示すような関数の [-2, -1] 区間における最小値を求める場合に対する値が設定されています.他の問題を実行する場合は,それらを適切に修正してください.なお,目的関数は,JavaScript の仕様に適合した形式で記述してあることに注意してください.
<P STYLE="text-align:center"><IMG SRC="gold.gif"></P>
</DL>
<DIV STYLE="text-align:center">
初期値:<INPUT ID="a" STYLE="font-size: 100%" TYPE="text" SIZE="5" VALUE="-2">,
<INPUT ID="b" 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>
目的関数: f(x) = <INPUT ID="func" STYLE="font-size: 100%" TYPE="text" SIZE="50" VALUE="x * x * x * x + 3.0 * x * x * x + 2.0 * x * x + 1.0">
<BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">実行</BUTTON><BR><BR>
結果:<INPUT ID="res" STYLE="font-size: 100%" TYPE="text" SIZE="40">
</DIV>
</BODY>
</HTML>
<?php
/*********************************************/
/* 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値 */
/* coded by Y.Suganuma */
/*********************************************/
$a = -2.0;
$b = -1.0;
$eps = 1.0e-10;
$max = 100;
$x = gold($a, $b, $eps, $val, $ind, $max, "snx");
printf("x %f val %f ind %d\n", $x, $val, $ind);
/****************/
/* 関数値の計算 */
/****************/
function snx($x)
{
return $x * $x * $x * $x + 3.0 * $x * $x * $x + 2.0 * $x * $x + 1.0;
}
/******************************************/
/* 黄金分割法(関数の最小値) */
/* a,b : 初期区間 a < b */
/* eps : 許容誤差 */
/* val : 間数値 */
/* ind : 計算状況 */
/* >= 0 : 正常終了(収束回数) */
/* = -1 : 収束せず */
/* max : 最大試行回数 */
/* fun : 関数値を計算する関数の名前 */
/* return : 結果 */
/******************************************/
function gold($a, $b, $eps, &$val, &$ind, $max, $fun)
{
$x = 0.0;
$tau = (sqrt(5.0) - 1.0) / 2.0;
$count = 0;
$ind = -1;
$x1 = $b - $tau * ($b - $a);
$x2 = $a + $tau * ($b - $a);
$f1 = $fun($x1);
$f2 = $fun($x2);
while ($count < $max && $ind < 0) {
$count += 1;
if ($f2 > $f1) {
if (abs($b-$a) < $eps && abs($b-$a) < $eps*abs($b)) {
$ind = 0;
$x = $x1;
$val = $f1;
}
else {
$b = $x2;
$x2 = $x1;
$x1 = $a + (1.0 - $tau) * ($b - $a);
$f2 = $f1;
$f1 = $fun($x1);
}
}
else {
if (abs($b-$a) < $eps && abs($b-$a) < $eps*abs($b)) {
$ind = 0;
$x = $x2;
$val = $f2;
$f1 = $f2;
}
else {
$a = $x1;
$x1 = $x2;
$x2 = $b - (1.0 - $tau) * ($b - $a);
$f1 = $f2;
$f2 = $fun($x2);
}
}
}
if ($ind == 0) {
$ind = $count;
$fa = $fun($a);
$fb = $fun($b);
if ($fb < $fa) {
$a = $b;
$fa = $fb;
}
if ($fa < $f1) {
$x = $a;
$val = $fa;
}
}
return $x;
}
?>
#********************************************/
# 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値 */
# coded by Y.Suganuma */
#********************************************/
#***************/
# 関数値の計算 */
#***************/
snx = Proc.new { |x|
x * x * x * x + 3.0 * x * x * x + 2.0 * x * x + 1.0
}
#*****************************************/
# 黄金分割法(関数の最小値) */
# a,b : 初期区間 a < b */
# eps : 許容誤差 */
# val : 間数値 */
# ind : 計算状況 */
# >= 0 : 正常終了(収束回数) */
# = -1 : 収束せず */
# max : 最大試行回数 */
# fun : 関数値を計算する関数の名前 */
# return : 結果 */
#*****************************************/
def gold(a, b, eps, val, ind, max, &fun)
x = 0.0
tau = (Math.sqrt(5.0) - 1.0) / 2.0
count = 0
ind[0] = -1
x1 = b - tau * (b - a)
x2 = a + tau * (b - a)
f1 = fun.call(x1)
f2 = fun.call(x2)
while count < max && ind[0] < 0
count += 1
if f2 > f1
if (b-a).abs() < eps && (b-a).abs() < eps*b.abs()
ind[0] = 0
x = x1
val[0] = f1
else
b = x2
x2 = x1
x1 = a + (1.0 - tau) * (b - a)
f2 = f1
f1 = fun.call(x1)
end
else
if (b-a).abs() < eps && (b-a).abs() < eps*b.abs()
ind[0] = 0
x = x2
val[0] = f2
f1 = f2
else
a = x1
x1 = x2
x2 = b - (1.0 - tau) * (b - a)
f1 = f2
f2 = fun.call(x2)
end
end
end
if ind[0] == 0
ind[0] = count
fa = fun.call(a)
fb = fun.call(b)
if fb < fa
a = b
fa = fb
end
if fa < f1
x = a
val[0] = fa
end
end
return x
end
ind = Array.new(1)
val = Array.new(1)
a = -2.0
b = -1.0
eps = 1.0e-10
max = 100
x = gold(a, b, eps, val, ind, max, &snx)
printf("x %f val %f ind %d\n", x, val[0], ind[0])
# -*- coding: UTF-8 -*-
import numpy as np
import sys
from math import *
############################################
# 黄金分割法(関数の最小値)
# a,b : 初期区間 a < b
# eps : 許容誤差
# val : 間数値
# ind : 計算状況
# >= 0 : 正常終了(収束回数)
# = -1 : 収束せず
# max : 最大試行回数
# fun : 関数値を計算する関数の名前
# return : 結果
# coded by Y.Suganuma
############################################
def gold(a, b, eps, val, ind, max, fun) :
x = 0.0
tau = (sqrt(5.0) - 1.0) / 2.0
count = 0
ind[0] = -1
x1 = b - tau * (b - a)
x2 = a + tau * (b - a)
f1 = fun(x1)
f2 = fun(x2)
while count < max and ind[0] < 0 :
count += 1
if f2 > f1 :
if (abs(b-a) < eps) and (abs(b-a) < eps*abs(b)) :
ind[0] = 0
x = x1
val[0] = f1
else :
b = x2
x2 = x1
x1 = a + (1.0 - tau) * (b - a)
f2 = f1
f1 = fun(x1)
else :
if (abs(b-a) < eps) and (abs(b-a) < eps*abs(b)) :
ind[0] = 0
x = x2
val[0] = f2
f1 = f2
else :
a = x1
x1 = x2
x2 = b - (1.0 - tau) * (b - a)
f1 = f2
f2 = fun(x2)
if ind[0] == 0 :
ind[0] = count
fa = fun(a)
fb = fun(b)
if fb < fa :
a = b
fa = fb
if fa < f1 :
x = a
val[0] = fa
return x
############################################
# 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値
# coded by Y.Suganuma
############################################
# 関数値の計算
def snx(x) :
return x * x * x * x + 3.0 * x * x * x + 2.0 * x * x + 1.0
# 設定と実行
a = -2.0
b = -1.0
eps = 1.0e-10
max = 100
val = np.empty(1, np.float)
ind = np.empty(1, np.int)
x = gold(a, b, eps, val, ind, max, snx)
print("x " + str(x) + " val " + str(val[0]) + " ind " + str(ind[0]))
/*********************************************/
/* 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値 */
/* coded by Y.Suganuma */
/*********************************************/
using System;
class Program
{
static void Main()
{
Test1 ts = new Test1();
}
}
class Test1
{
public Test1()
{
double a = -2.0;
double b = -1.0;
double eps = 1.0e-10;
double val = 0.0;
int max = 100;
int ind = 0;
double x = gold(a, b, eps, ref val, ref ind, max, snx);
Console.WriteLine("x " + x + " val " + val + " ind " + ind);
}
// 関数値の計算
double snx(double x)
{
return x * x * x * x + 3.0 * x * x * x + 2.0 * x * x + 1.0;
}
/************************************************/
/* 黄金分割法(関数の最小値) */
/* a,b : 初期区間 a < b */
/* eps : 許容誤差 */
/* val : 間数値 */
/* ind : 計算状況 */
/* >= 0 : 正常終了(収束回数) */
/* = -1 : 収束せず */
/* max : 最大試行回数 */
/* fn : 関数値を計算する関数 */
/* return : 結果 */
/************************************************/
double gold(double a, double b, double eps, ref double val, ref int ind, int max,
Func<double, double> fn)
{
ind = -1;
int count = 0;
double tau = (Math.Sqrt(5.0) - 1.0) / 2.0;
double x1 = b - tau * (b - a);
double x2 = a + tau * (b - a);
double f1 = fn(x1);
double f2 = fn(x2);
double x = 0.0;
while (count < max && ind < 0) {
count += 1;
if (f2 > f1) {
if (Math.Abs(b-a) < eps && Math.Abs(b-a) < eps*Math.Abs(b)) {
ind = 0;
x = x1;
val = f1;
}
else {
b = x2;
x2 = x1;
x1 = a + (1.0 - tau) * (b - a);
f2 = f1;
f1 = fn(x1);
}
}
else {
if (Math.Abs(b-a) < eps && Math.Abs(b-a) < eps*Math.Abs(b)) {
ind = 0;
x = x2;
val = f2;
f1 = f2;
}
else {
a = x1;
x1 = x2;
x2 = b - (1.0 - tau) * (b - a);
f1 = f2;
f2 = fn(x2);
}
}
}
if (ind == 0) {
ind = count;
double fa = fn(a);
double fb = fn(b);
if (fb < fa) {
a = b;
fa = fb;
}
if (fa < f1) {
x = a;
val = fa;
}
}
return x;
}
}
'''''''''''''''''''''''''''''''''''''''''''''
' 黄金分割法によるy=x^4+3x^3+2x^2+1の最小値 '
' coded by Y.Suganuma '
'''''''''''''''''''''''''''''''''''''''''''''
Module Test
Sub Main()
Dim a As Double = -2.0
Dim b As Double = -1.0
Dim eps As Double = 1.0e-10
Dim val As Double = 0.0
Dim max As Integer = 100
Dim ind As Integer = 0
' 関数値の計算(ラムダ式)
Dim snx = Function(v) As Double
Return v * v * v * v + 3.0 * v * v * v + 2.0 * v * v + 1.0
End Function
' 実行
Dim x As Double = gold(a, b, eps, val, ind, max, snx)
Console.WriteLine("x " & x & " val " & val & " ind " & ind)
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''
' 黄金分割法(関数の最小値) '
' a,b : 初期区間 a < b '
' eps : 許容誤差 '
' val : 間数値 '
' ind : 計算状況 '
' >= 0 : 正常終了(収束回数) '
' = -1 : 収束せず '
' max : 最大試行回数 '
' fn : 関数値を計算する関数 '
' return : 結果 '
''''''''''''''''''''''''''''''''''''''''''''''''
Function gold(a As Double, b As Double, eps As Double, ByRef val As Double,
ByRef ind As Integer, max As Integer, fn As Func(Of Double, Double))
ind = -1
Dim count As Integer = 0
Dim tau As Double = (Math.Sqrt(5.0) - 1.0) / 2.0
Dim x1 As Double = b - tau * (b - a)
Dim x2 As Double = a + tau * (b - a)
Dim f1 As Double = fn(x1)
Dim f2 As Double = fn(x2)
Dim x As Double = 0.0
Do while count < max and ind < 0
count += 1
If f2 > f1
If Math.Abs(b-a) < eps and Math.Abs(b-a) < eps*Math.Abs(b)
ind = 0
x = x1
val = f1
Else
b = x2
x2 = x1
x1 = a + (1.0 - tau) * (b - a)
f2 = f1
f1 = fn(x1)
End If
Else
If Math.Abs(b-a) < eps and Math.Abs(b-a) < eps*Math.Abs(b)
ind = 0
x = x2
val = f2
f1 = f2
Else
a = x1
x1 = x2
x2 = b - (1.0 - tau) * (b - a)
f1 = f2
f2 = fn(x2)
End If
End If
Loop
If ind = 0
ind = count
Dim fa As Double = fn(a)
Dim fb As Double = fn(b)
If fb < fa
a = b
fa = fb
End If
If fa < f1
x = a
val = fa
End If
End If
Return x
End Function
End Module
| 情報学部 | 菅沼ホーム | 目次 | 索引 |