情報学部 | 菅沼ホーム | 目次 | 索引 |
/****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ #include <stdio.h> #include <math.h> int gauss(double **, int, int, double); double *least(int, int, double *, double *); int main() { double *x, *y, *z; int i1, m, n; scanf("%d %d", &m, &n); // 多項式の次数とデータの数 x = new double [n]; y = new double [n]; for (i1 = 0; i1 < n; i1++) // データ scanf("%lf %lf", &x[i1], &y[i1]); z = least(m, n, x, y); if (z != NULL) { printf("結果\n"); for (i1 = 0; i1 < m+1; i1++) printf(" %d 次の係数 %f\n", m-i1, z[i1]); delete [] z; } else printf("***error 逆行列を求めることができませんでした\n"); delete [] x; delete [] y; return 0; } /******************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* return : 多項式の係数(高次から) */ /* エラーの場合はNULLを返す */ /******************************************/ double *least(int m, int n, double *x, double *y) { double **A, **w, *z, x1, x2; int i1, i2, i3, sw; m++; z = new double [m]; w = new double * [m]; for (i1 = 0; i1 < m; i1++) w[i1] = new double [m+1]; A = new double * [n]; for (i1 = 0; i1 < n; i1++) { A[i1] = new double [m]; A[i1][m-2] = x[i1]; A[i1][m-1] = 1.0; x1 = A[i1][m-2]; x2 = x1; for (i2 = m-3; i2 >= 0; i2--) { x2 *= x1; A[i1][i2] = x2; } } for (i1 = 0; i1 < m; i1++) { for (i2 = 0; i2 < m; i2++) { w[i1][i2] = 0.0; for (i3 = 0; i3 < n; i3++) w[i1][i2] += A[i3][i1] * A[i3][i2]; } } for (i1 = 0; i1 < m; i1++) { w[i1][m] = 0.0; for (i2 = 0; i2 < n; i2++) w[i1][m] += A[i2][i1] * y[i2]; } sw = gauss(w, m, 1, 1.0e-10); if (sw == 0) { for (i1 = 0; i1 < m; i1++) z[i1] = w[i1][m]; } else z = NULL; for (i1 = 0; i1 < n; i1++) delete [] A[i1]; for (i1 = 0; i1 < m; i1++) delete [] w[i1]; delete [] A; delete [] w; return z; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 正則性を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ int gauss(double **w, int n, int m, double eps) { double y1, y2; int ind = 0, nm, m1, m2, i1, i2, i3; nm = n + m; for (i1 = 0; i1 < n && ind == 0; i1++) { y1 = .0; m1 = i1 + 1; m2 = 0; for (i2 = i1; i2 < n; i2++) { y2 = fabs(w[i2][i1]); if (y1 < y2) { y1 = y2; m2 = i2; } } if (y1 < eps) ind = 1; else { for (i2 = i1; i2 < nm; i2++) { y1 = w[i1][i2]; w[i1][i2] = w[m2][i2]; w[m2][i2] = y1; } y1 = 1.0 / w[i1][i1]; for (i2 = m1; i2 < nm; i2++) w[i1][i2] *= y1; for (i2 = 0; i2 < n; i2++) { if (i2 != i1) { for (i3 = m1; i3 < nm; i3++) w[i2][i3] -= w[i2][i1] * w[i1][i3]; } } } } return(ind); } /* -----------データ例1(コメント部分を除いて下さい)--------- 1 10 // 多項式の次数とデータの数 0 2.450 // 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 */
/****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.util.StringTokenizer; public class Test { public static void main(String args[]) throws IOException { double x[], y[], z[]; int i1, m, n, sw; StringTokenizer str; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // 多項式の次数とデータの数 str = new StringTokenizer(in.readLine(), " "); m = Integer.parseInt(str.nextToken()); n = Integer.parseInt(str.nextToken()); x = new double [n]; y = new double [n]; z = new double [m+1]; // データ for (i1 = 0; i1 < n; i1++) { str = new StringTokenizer(in.readLine(), " "); x[i1] = Double.parseDouble(str.nextToken()); y[i1] = Double.parseDouble(str.nextToken()); } sw = least(m, n, x, y, z); if (sw == 0) { System.out.println("結果"); for (i1 = 0; i1 < m+1; i1++) System.out.println(" " + (m-i1) + " 次の係数 " + z[i1]); } else System.out.println("***error 逆行列を求めることができませんでした"); } /*************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* z : 多項式の係数(高次から) */ /* return : =0 : 正常 */ /* =1 : エラー */ /*************************************/ static int least(int m, int n, double x[], double y[], double z[]) { double A[][], w[][], x1, x2; int i1, i2, i3, sw = 0; m++; w = new double [m][m+1]; A = new double [n][m]; for (i1 = 0; i1 < n; i1++) { A[i1][m-2] = x[i1]; A[i1][m-1] = 1.0; x1 = A[i1][m-2]; x2 = x1; for (i2 = m-3; i2 >= 0; i2--) { x2 *= x1; A[i1][i2] = x2; } } for (i1 = 0; i1 < m; i1++) { for (i2 = 0; i2 < m; i2++) { w[i1][i2] = 0.0; for (i3 = 0; i3 < n; i3++) w[i1][i2] += A[i3][i1] * A[i3][i2]; } } for (i1 = 0; i1 < m; i1++) { w[i1][m] = 0.0; for (i2 = 0; i2 < n; i2++) w[i1][m] += A[i2][i1] * y[i2]; } sw = gauss(w, m, 1, 1.0e-10); if (sw == 0) { for (i1 = 0; i1 < m; i1++) z[i1] = w[i1][m]; } else sw = 1; return sw; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 逆行列の存在を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ static int gauss(double w[][], int n, int m, double eps) { double y1, y2; int ind = 0, nm, m1, m2, i1, i2, i3; nm = n + m; for (i1 = 0; i1 < n && ind == 0; i1++) { y1 = .0; m1 = i1 + 1; m2 = 0; // ピボット要素の選択 for (i2 = i1; i2 < n; i2++) { y2 = Math.abs(w[i2][i1]); if (y1 < y2) { y1 = y2; m2 = i2; } } // 逆行列が存在しない if (y1 < eps) ind = 1; // 逆行列が存在する else { // 行の入れ替え for (i2 = i1; i2 < nm; i2++) { y1 = w[i1][i2]; w[i1][i2] = w[m2][i2]; w[m2][i2] = y1; } // 掃き出し操作 y1 = 1.0 / w[i1][i1]; for (i2 = m1; i2 < nm; i2++) w[i1][i2] *= y1; for (i2 = 0; i2 < n; i2++) { if (i2 != i1) { for (i3 = m1; i3 < nm; i3++) w[i2][i3] -= w[i2][i1] * w[i1][i3]; } } } } return(ind); } } /* -----------データ例1(コメント部分を除いて下さい)--------- 1 10 // 多項式の次数とデータの数 0 2.450 // 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 */
<!DOCTYPE HTML> <HTML> <HEAD> <TITLE>最小二乗法(多項式近似)</TITLE> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8"> <SCRIPT TYPE="text/javascript"> function main() { // データ let m = parseInt(document.getElementById("m").value); let n = parseInt(document.getElementById("n").value); let x = new Array(); let y = new Array(); let z = new Array(); let s = (document.getElementById("data").value).split(/ {1,}|\n{1,}/); let k = 0; for (let i1 = 0; i1 < 2*n; i1 += 2) { x[k] = parseFloat(s[i1]); y[k] = parseFloat(s[i1+1]); k++; } // 計算 let sw = least(m, n, x, y, z); if (sw > 0) document.getElementById("ans").value = "逆行列が存在しない"; else { let str = ""; for (let i1 = 0; i1 < m+1; i1++) str = str + (m-i1) + " 次の係数 " + z[i1] + "\n"; document.getElementById("ans").value = str; } } /*************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* z : 多項式の係数(高次から) */ /* return : =0 : 正常 */ /* =1 : エラー */ /*************************************/ function least(m, n, x, y, z) { let x1; let x2; let i1; let i2; let i3; let sw = 0; m++; let w = new Array(); for (i1 = 0; i1 < m; i1++) w[i1] = new Array(); let A = new Array(); for (i1 = 0; i1 < n; i1++) A[i1] = new Array(); for (i1 = 0; i1 < n; i1++) { A[i1][m-2] = x[i1]; A[i1][m-1] = 1.0; x1 = A[i1][m-2]; x2 = x1; for (i2 = m-3; i2 >= 0; i2--) { x2 *= x1; A[i1][i2] = x2; } } for (i1 = 0; i1 < m; i1++) { for (i2 = 0; i2 < m; i2++) { w[i1][i2] = 0.0; for (i3 = 0; i3 < n; i3++) w[i1][i2] += A[i3][i1] * A[i3][i2]; } } for (i1 = 0; i1 < m; i1++) { w[i1][m] = 0.0; for (i2 = 0; i2 < n; i2++) w[i1][m] += A[i2][i1] * y[i2]; } sw = gauss(w, m, 1, 1.0e-10); if (sw == 0) { for (i1 = 0; i1 < m; i1++) z[i1] = w[i1][m]; } else sw = 1; return sw; } /******************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 逆行列の存在を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /******************************************/ function gauss(w, n, m, eps) { let y1; let y2; let ind = 0; let nm; let m1; let m2; let i1; let i2; let i3; nm = n + m; for (i1 = 0; i1 < n && ind == 0; i1++) { y1 = .0; m1 = i1 + 1; m2 = 0; // ピボット要素の選択 for (i2 = i1; i2 < n; i2++) { y2 = Math.abs(w[i2][i1]); if (y1 < y2) { y1 = y2; m2 = i2; } } // 逆行列が存在しない if (y1 < eps) ind = 1; // 逆行列が存在する else { // 行の入れ替え for (i2 = i1; i2 < nm; i2++) { y1 = w[i1][i2]; w[i1][i2] = w[m2][i2]; w[m2][i2] = y1; } // 掃き出し操作 y1 = 1.0 / w[i1][i1]; for (i2 = m1; i2 < nm; i2++) w[i1][i2] *= y1; for (i2 = 0; i2 < n; i2++) { if (i2 != i1) { for (i3 = m1; i3 < nm; i3++) w[i2][i3] -= w[i2][i1] * w[i1][i3]; } } } } return(ind); } </SCRIPT> </HEAD> <BODY STYLE="font-size: 130%; background-color: #eeffee;"> <H2 STYLE="text-align:center"><B>最小二乗法(多項式近似)</B></H2> <DL> <DT> テキストフィールドおよびテキストエリアには,例として,テキストエリアに与えられた 10 個の点を直線で近似する場合に対する値が設定されています.他の問題を実行する場合は,それらを適切に修正してください. </DL> <DIV STYLE="text-align:center"> 多項式の次数:<INPUT ID="m" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="1"> データの数:<INPUT ID="n" STYLE="font-size: 100%" TYPE="text" SIZE="2" VALUE="10"><BR><BR> データ(x y):<TEXTAREA ID="data" COLS="30" ROWS="15" STYLE="font-size: 100%"> 0 2.450 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 </TEXTAREA> <BUTTON STYLE="font-size: 100%; background-color: pink" onClick="main()">OK</BUTTON><BR><BR> <TEXTAREA ID="ans" COLS="40" ROWS="5" STYLE="font-size: 100%;"></TEXTAREA> </DIV> </BODY> </HTML>
<?php /****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ fscanf(STDIN, "%d %d", $m, $n); // 多項式の次数とデータの数 $x = array($n); $y = array($n); for ($i1 = 0; $i1 < $n; $i1++) // データ fscanf(STDIN, "%lf %lf", $x[$i1], $y[$i1]); $z = least($m, $n, $x, $y); if ($z != NULL) { printf("結果\n"); for ($i1 = 0; $i1 < $m+1; $i1++) printf(" %d 次の係数 %f\n", $m-$i1, $z[$i1]); } else printf("***error 逆行列を求めることができませんでした\n"); /******************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* return : 多項式の係数(高次から) */ /* エラーの場合はNULLを返す */ /******************************************/ function least($m, $n, $x, $y) { $m++; $z = array($m); $w = array($m); for ($i1 = 0; $i1 < $m; $i1++) $w[$i1] = array($m+1); $A = array($n); for ($i1 = 0; $i1 < $n; $i1++) { $A[$i1] = array($m); $A[$i1][$m-2] = $x[$i1]; $A[$i1][$m-1] = 1.0; $x1 = $A[$i1][$m-2]; $x2 = $x1; for ($i2 = $m-3; $i2 >= 0; $i2--) { $x2 *= $x1; $A[$i1][$i2] = $x2; } } for ($i1 = 0; $i1 < $m; $i1++) { for ($i2 = 0; $i2 < $m; $i2++) { $w[$i1][$i2] = 0.0; for ($i3 = 0; $i3 < $n; $i3++) $w[$i1][$i2] += $A[$i3][$i1] * $A[$i3][$i2]; } } for ($i1 = 0; $i1 < $m; $i1++) { $w[$i1][$m] = 0.0; for ($i2 = 0; $i2 < $n; $i2++) $w[$i1][$m] += $A[$i2][$i1] * $y[$i2]; } $sw = gauss($w, $m, 1, 1.0e-10); if ($sw == 0) { for ($i1 = 0; $i1 < $m; $i1++) $z[$i1] = $w[$i1][$m]; } else $z = NULL; return $z; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 正則性を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ function gauss(&$w, $n, $m, $eps) { $ind = 0; $nm = $n + $m; for ($i1 = 0; $i1 < $n && $ind == 0; $i1++) { $y1 = .0; $m1 = $i1 + 1; $m2 = 0; for ($i2 = $i1; $i2 < $n; $i2++) { $y2 = abs($w[$i2][$i1]); if ($y1 < $y2) { $y1 = $y2; $m2 = $i2; } } if ($y1 < $eps) $ind = 1; else { for ($i2 = $i1; $i2 < $nm; $i2++) { $y1 = $w[$i1][$i2]; $w[$i1][$i2] = $w[$m2][$i2]; $w[$m2][$i2] = $y1; } $y1 = 1.0 / $w[$i1][$i1]; for ($i2 = $m1; $i2 < $nm; $i2++) $w[$i1][$i2] *= $y1; for ($i2 = 0; $i2 < $n; $i2++) { if ($i2 != $i1) { for ($i3 = $m1; $i3 < $nm; $i3++) $w[$i2][$i3] -= $w[$i2][$i1] * $w[$i1][$i3]; } } } } return($ind); } /* -----------データ例1(コメント部分を除いて下さい)--------- 1 10 // 多項式の次数とデータの数 0 2.450 // 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 */ ?>
############################ # 最小二乗法(多項式近似) # coded by Y.Suganuma ############################ ############################################ # 線形連立方程式を解く(逆行列を求める) # w : 方程式の左辺及び右辺 # n : 方程式の数 # m : 方程式の右辺の列の数 # eps : 逆行列の存在を判定する規準 # return : =0 : 正常 # =1 : 逆行列が存在しない # coded by Y.Suganuma ############################################ def gauss(w, n, m, eps) nm = n + m; ind = 0 for i1 in 0 ... n y1 = 0.0 m1 = i1 + 1 m2 = 0 # ピボット要素の選択 for i2 in i1 ... n y2 = w[i2][i1].abs() if y1 < y2 y1 = y2 m2 = i2 end end # 逆行列が存在しない if y1 < eps ind = 1 break # 逆行列が存在する else # 行の入れ替え for i2 in i1 ... nm y1 = w[i1][i2] w[i1][i2] = w[m2][i2] w[m2][i2] = y1 end # 掃き出し操作 y1 = 1.0 / w[i1][i1] for i2 in m1 ... nm w[i1][i2] *= y1 end for i2 in 0 ... n if i2 != i1 for i3 in m1 ... nm w[i2][i3] -= (w[i2][i1] * w[i1][i3]) end end end end end return ind end ######################################### # 最小二乗法 # m : 多項式の次数 # n : データの数 # x,y : データ # return : 多項式の係数(高次から) # エラーの場合はNULLを返す # coded by Y.Suganuma ######################################### def least(m, n, x, y) m += 1 z = Array.new(m) w = Array.new(m) for i1 in 0 ... m w[i1] = Array.new(m+1) end a = Array.new(n) for i1 in 0 ... n a[i1] = Array.new(m) end for i1 in 0 ... n a[i1][m-2] = x[i1] a[i1][m-1] = 1.0 x1 = a[i1][m-2] x2 = x1 i2 = m - 3 while i2 > -1 x2 *= x1 a[i1][i2] = x2 i2 -= 1 end end for i1 in 0 ... m for i2 in 0 ... m w[i1][i2] = 0.0 for i3 in 0 ... n w[i1][i2] += a[i3][i1] * a[i3][i2] end end end for i1 in 0 ... m w[i1][m] = 0.0 for i2 in 0 ... n w[i1][m] += a[i2][i1] * y[i2] end end sw = gauss(w, m, 1, 1.0e-10) if sw == 0 for i1 in 0 ... m z[i1] = w[i1][m] end else z = Array.new(0) end return z end s = gets().split(" ") m = Integer(s[0]) # 多項式の次数 n = Integer(s[1]) # データの数 x = Array.new(n) y = Array.new(n) for i1 in 0 ... n # データ s = gets().split() x[i1] = Float(s[0]) y[i1] = Float(s[1]) end z = least(m, n, x, y) if z.size > 0 print("結果\n") for i1 in 0 ... m+1 print(" " + String(m-i1) + " 次の係数 " + String(z[i1]) + "\n") end else print("***error 逆行列を求めることができませんでした\n") end =begin ------------データ例1(コメント部分を除いて下さい)-------- 1 10 # 多項式の次数とデータの数 0 2.450 # 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 =end
# -*- coding: UTF-8 -*- import numpy as np import sys from math import * ############################################ # 線形連立方程式を解く(逆行列を求める) # w : 方程式の左辺及び右辺 # n : 方程式の数 # m : 方程式の右辺の列の数 # eps : 逆行列の存在を判定する規準 # return : =0 : 正常 # =1 : 逆行列が存在しない # coded by Y.Suganuma ############################################ def gauss(w, n, m, eps) : nm = n + m ind = 0 for i1 in range(0, n) : y1 = 0.0 m1 = i1 + 1 m2 = 0 # ピボット要素の選択 for i2 in range(i1, n) : y2 = abs(w[i2][i1]) if y1 < y2 : y1 = y2 m2 = i2 # 逆行列が存在しない if y1 < eps : ind = 1 break # 逆行列が存在する else : # 行の入れ替え for i2 in range(i1, nm) : y1 = w[i1][i2] w[i1][i2] = w[m2][i2] w[m2][i2] = y1 # 掃き出し操作 y1 = 1.0 / w[i1][i1] for i2 in range(m1, nm) : w[i1][i2] *= y1 for i2 in range(0, n) : if i2 != i1 : for i3 in range(m1, nm) : w[i2][i3] -= (w[i2][i1] * w[i1][i3]) return ind ######################################### # 最小二乗法 # m : 多項式の次数 # n : データの数 # x,y : データ # return : 多項式の係数(高次から) # エラーの場合はNULLを返す # coded by Y.Suganuma ######################################### def least(m, n, x, y) : m += 1 z = np.empty(m, np.float) w = np.empty((m, m+1), np.float) A = np.empty((n, m), np.float) for i1 in range(0, n) : A[i1][m-2] = x[i1] A[i1][m-1] = 1.0 x1 = A[i1][m-2] x2 = x1 for i2 in range(m-3, -1, -1) : x2 *= x1 A[i1][i2] = x2 for i1 in range(0, m) : for i2 in range(0, m) : w[i1][i2] = 0.0 for i3 in range(0, n) : w[i1][i2] += A[i3][i1] * A[i3][i2] for i1 in range(0, m) : w[i1][m] = 0.0 for i2 in range(0, n) : w[i1][m] += A[i2][i1] * y[i2] sw = gauss(w, m, 1, 1.0e-10) if sw == 0 : for i1 in range(0, m) : z[i1] = w[i1][m] else : z = np.empty(0, np.float) return z ############################ # 最小二乗法(多項式近似) # coded by Y.Suganuma ############################ line = sys.stdin.readline() s = line.split() m = int(s[0]) # 多項式の次数 n = int(s[1]) # データの数 x = np.empty(n, np.float) y = np.empty(n, np.float) for i1 in range(0, n) : # データ line = sys.stdin.readline() s = line.split() x[i1] = float(s[0]) y[i1] = float(s[1]) z = least(m, n, x, y) if z.size > 0 : print("結果") for i1 in range(0, m+1) : print(" " + str(m-i1) + " 次の係数 " + str(z[i1])) else : print("***error 逆行列を求めることができませんでした") """ ------------データ例1(コメント部分を除いて下さい)-------- 1 10 # 多項式の次数とデータの数 0 2.450 # 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 """
/****************************/ /* 最小二乗法(多項式近似) */ /* coded by Y.Suganuma */ /****************************/ using System; class Program { static void Main() { Test1 ts = new Test1(); } } class Test1 { public Test1() { char[] charSep = new char[] {' '}; // 多項式の次数とデータの数 String[] str = Console.ReadLine().Split(charSep, StringSplitOptions.RemoveEmptyEntries); int m = int.Parse(str[0]); int n = int.Parse(str[1]); double[] x = new double [n]; double[] y = new double [n]; double[] z = new double [m+1]; // データ for (int i1 = 0; i1 < n; i1++) { str = Console.ReadLine().Split(charSep, StringSplitOptions.RemoveEmptyEntries); x[i1] = double.Parse(str[0]); y[i1] = double.Parse(str[1]); } int sw = least(m, n, x, y, z); if (sw == 0) { Console.WriteLine("結果"); for (int i1 = 0; i1 < m+1; i1++) Console.WriteLine(" " + (m-i1) + " 次の係数 " + z[i1]); } else Console.WriteLine("***error 逆行列を求めることができませんでした"); } /*************************************/ /* 最初2乗法 */ /* m : 多項式の次数 */ /* n : データの数 */ /* x,y : データ */ /* z : 多項式の係数(高次から) */ /* return : =0 : 正常 */ /* =1 : エラー */ /*************************************/ int least(int m, int n, double[] x, double[] y, double[] z) { m++; double[][] w = new double [m][]; for (int i1 = 0; i1 < m; i1++) w[i1] = new double[m+1]; double[][] A = new double [n][]; for (int i1 = 0; i1 < n; i1++) A[i1] = new double[m]; for (int i1 = 0; i1 < n; i1++) { A[i1][m-2] = x[i1]; A[i1][m-1] = 1.0; double x1 = A[i1][m-2]; double x2 = x1; for (int i2 = m-3; i2 >= 0; i2--) { x2 *= x1; A[i1][i2] = x2; } } for (int i1 = 0; i1 < m; i1++) { for (int i2 = 0; i2 < m; i2++) { w[i1][i2] = 0.0; for (int i3 = 0; i3 < n; i3++) w[i1][i2] += A[i3][i1] * A[i3][i2]; } } for (int i1 = 0; i1 < m; i1++) { w[i1][m] = 0.0; for (int i2 = 0; i2 < n; i2++) w[i1][m] += A[i2][i1] * y[i2]; } int sw = gauss(w, m, 1, 1.0e-10); if (sw == 0) { for (int i1 = 0; i1 < m; i1++) z[i1] = w[i1][m]; } else sw = 1; return sw; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 逆行列の存在を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ int gauss(double[][] w, int n, int m, double eps) { int ind = 0; int nm = n + m; for (int i1 = 0; i1 < n && ind == 0; i1++) { double y1 = .0; int m1 = i1 + 1; int m2 = 0; // ピボット要素の選択 for (int i2 = i1; i2 < n; i2++) { double y2 = Math.Abs(w[i2][i1]); if (y1 < y2) { y1 = y2; m2 = i2; } } // 逆行列が存在しない if (y1 < eps) ind = 1; // 逆行列が存在する else { // 行の入れ替え for (int i2 = i1; i2 < nm; i2++) { y1 = w[i1][i2]; w[i1][i2] = w[m2][i2]; w[m2][i2] = y1; } // 掃き出し操作 y1 = 1.0 / w[i1][i1]; for (int i2 = m1; i2 < nm; i2++) w[i1][i2] *= y1; for (int i2 = 0; i2 < n; i2++) { if (i2 != i1) { for (int i3 = m1; i3 < nm; i3++) w[i2][i3] -= w[i2][i1] * w[i1][i3]; } } } } return ind; } } /* -----------データ例1(コメント部分を除いて下さい)--------- 1 10 // 多項式の次数とデータの数 0 2.450 // 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 */
'**************************' ' 最小二乗法(多項式近似) ' ' coded by Y.Suganuma ' '**************************' Imports System.Text.RegularExpressions Module Test Sub Main() Dim MS As Regex = New Regex("\s+") ' 多項式の次数とデータの数 Dim str() As String = MS.Split(Console.ReadLine().Trim()) Dim m As Integer = Integer.Parse(str(0)) Dim n As Integer = Integer.Parse(str(1)) Dim x(n) As Double Dim y(n) As Double Dim z(m+1) As Double ' データ For i1 As Integer = 0 To n-1 str = MS.Split(Console.ReadLine().Trim()) x(i1) = Double.Parse(str(0)) y(i1) = Double.Parse(str(1)) Next Dim sw As Integer = least(m, n, x, y, z) If sw = 0 Console.WriteLine("結果") For i1 As Integer = 0 To m Console.WriteLine(" " & (m-i1) & " 次の係数 " & z(i1)) Next Else Console.WriteLine("***error 逆行列を求めることができませんでした") End If End Sub '***********************************' ' 最初2乗法 ' ' m : 多項式の次数 ' ' n : データの数 ' ' x,y : データ ' ' z : 多項式の係数(高次から) ' ' return : =0 : 正常 ' ' =1 : エラー ' '***********************************' Function least(m As Integer, n As Integer, x() As Double, y() As Double, z() As Double) m += 1 Dim w(m,m+1) As Double Dim A(n,m) As Double For i1 As Integer = 0 To n-1 A(i1,m-2) = x(i1) A(i1,m-1) = 1.0 Dim x1 As Double = A(i1,m-2) Dim x2 As Double = x1 For i2 As Integer = m-3 To 0 Step -1 x2 *= x1 A(i1,i2) = x2 Next Next For i1 As Integer = 0 To m-1 For i2 As Integer = 0 To m-1 w(i1,i2) = 0.0 For i3 As Integer = 0 To n-1 w(i1,i2) += A(i3,i1) * A(i3,i2) Next Next Next For i1 As Integer = 0 To m-1 w(i1,m) = 0.0 For i2 As Integer = 0 To n-1 w(i1,m) += A(i2,i1) * y(i2) Next Next Dim sw As Integer = gauss(w, m, 1, 1.0e-10) If sw = 0 For i1 As Integer = 0 To m-1 z(i1) = w(i1,m) Next Else sw = 1 End If Return sw End Function '''''''''''''''''''''''''''''''''''''''''' ' 線形連立方程式を解く(逆行列を求める) ' ' w : 方程式の左辺及び右辺 ' ' n : 方程式の数 ' ' m : 方程式の右辺の列の数 ' ' eps : 逆行列の存在を判定する規準 ' ' return : =0 : 正常 ' ' =1 : 逆行列が存在しない ' '''''''''''''''''''''''''''''''''''''''''' Function gauss(w(,) As Double, n As Integer, m As Integer, eps As Double) As Integer Dim ind As Integer = 0 Dim nm As Integer = n + m Dim i1 As Integer = 0 Do While i1 < n and ind = 0 Dim y1 As Double = 0.0 Dim m1 As Integer = i1 + 1 Dim m2 As Integer = 0 ' ピボット要素の選択 For i2 As Integer = i1 To n-1 Dim y2 As Double = Math.Abs(w(i2,i1)) If y1 < y2 y1 = y2 m2 = i2 End If Next ' 逆行列が存在しない If y1 < eps ind = 1 ' 逆行列が存在する Else ' 行の入れ替え For i2 As Integer = i1 To nm-1 y1 = w(i1,i2) w(i1,i2) = w(m2,i2) w(m2,i2) = y1 Next ' 掃き出し操作 y1 = 1.0 / w(i1,i1) For i2 As Integer = m1 To nm-1 w(i1,i2) *= y1 Next For i2 As Integer = 0 To n-1 If i2 <> i1 For i3 As Integer = m1 To nm-1 w(i2,i3) -= w(i2,i1) * w(i1,i3) Next End If Next End If i1 += 1 Loop Return ind End Function End Module /* -----------データ例1(コメント部分を除いて下さい)--------- 1 10 // 多項式の次数とデータの数 0 2.450 // 以下,(x, y) 1 2.615 2 3.276 3 3.294 4 3.778 5 4.009 6 3.920 7 4.267 8 4.805 9 5.656 -------------------------データ例2------------------------- 2 6 10 28.2 15 47.0 20 44.4 26 32.8 32 20.8 40 0.8 */
情報学部 | 菅沼ホーム | 目次 | 索引 |