print 3 + 5, "\n"; print 3 - 5, "\n"; print 3 * 5, "\n"; print 3 ** 5, "\n"; print 5 / 3, "\n"; print int(5 / 3), "\n"; print 5 % 3, "\n"; printf "%3d\n", 3 * 5; printf "%23.20f\n", 5 / 3; my $i = 3 * 5; print "3 * 5 = ".$i."\n"; print "3 * 5 = ", $i, "\n"; print "3 * 5 = $i\n"; printf "3 * 5 = %d\n", $i; for (1..9) { print "$_, "; } print "\n"; for (1..9) { if ($_ % 3 == 0) { print "$_, "; } } print "\n"; for (1..9) { print "$_, " if ($_ % 3 == 0) } print "\n"; for (1..9) { print "$_, " unless ($_ % 3) } print "\n"; use strict; use warnings; my $sum = 0; for (1..99) { if ($_ % 3 == 0) { $sum += $_; } } print "$sum\n"; map {print $_, ","} 1..9 map {print $_, ","} grep {$_ % 3 == 0} 1..9 use List::Util; print List::Util::reduce {$a + $b} grep {$_ % 3 == 0} 1..99 print List::Util::sum grep {$_ % 3 == 0} 1..99 use strict; use warnings; # 初項:a, 公差:a で 上限:lim の数列の総和を返す関数 sub sn { my ($a, $lim) = @_; my $n = int($lim / $a); # 項数:n = 上限:lim / 公差:a my $l = $n * $a; # 末項:l = 項数:n * 公差:a ($a + $l) * $n / 2; # 総和:sn = (初項:a + 末項:l) * 項数:n / 2 } # 3 の倍数の合計 my $sum = sn(3, 999); print $sum, "\n"; # 10000 までの 自然数の和 # 項目数 n = 10000 my $n = 10000; print($n * ($n + 1) / 2, "\n"); # 10000 までの 偶数の和 # 項目数 n = 5000 my $n = 10000 / 2; print($n * ($n + 1), "\n"); # 10000 までの 奇数の和 # 項目数 n = 5000 my $n = 10000 / 2; print($n ** 2, "\n"); # 1000 までの 自然数の2乗の和 my $n = 1000; print($n * ($n + 1) * (2 * $n + 1) / 6, "\n"); # 100 までの 自然数の3乗の和 my $n = 100; print(($n ** 2) * (($n + 1) ** 2) / 4, "\n"); # 初項 2, 公比 3, 項数 10 の等比数列の和 my $n = 10; my $a = 2; my $r = 3; print(($a * (($r ** $n) - 1)) / ($r - 1), "\n"); $a = 5; # 初項 5 $d = 3; # 公差 3 $n = 10; # 項数 10 $p = 1; # 積 for (1..$n) { $m = $a + ($d * ($_ - 1)); $p *= $m; } print $p; sub product { my ($m, $d, $n) = @_; if ($n == 0) { 1 } else { $m * product($m + $d, $d, $n - 1) } } # 初項 5, 公差 3, 項数 10 の数列の積を表示する print product(5, 3, 10); # 階乗を求める関数 sub Fact { my ($n) = @_; if ($n <= 1) { 1; } else { $n * Fact($n - 1); } } # 10の階乗 print Fact(10), "\n"; print 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1, "\n"; # 下降階乗冪 sub FallingFact { my ($x, $n) = @_; if ($n <= 1) { $x; } else { $x * FallingFact($x - 1, $n - 1); } } # 10 から 6 までの 総乗 print FallingFact(10, 5), "\n"; print 10 * 9 * 8 * 7 * 6, "\n"; # 上昇階乗冪 sub RisingFact { my ($x, $n) = @_; if ($n <= 1) { $x; } else { $x * RisingFact($x + 1, $n - 1); } } # 10 から 14 までの 総乗 print RisingFact(10, 5), "\n"; print 10 * 11 * 12 * 13 * 14, "\n"; # 階乗 sub Fact { my ($n) = @_; if ($n <= 1) { 1; } else { $n * Fact($n - 1); } } # 下降階乗冪 sub FallingFact { my ($x, $n) = @_; if ($n <= 1) { $x; } else { $x * FallingFact($x - 1, $n - 1); } } # 順列 (異なる 10 個のものから 5 個取ってできる順列の総数) $n = 10; $r = 5; print Fact($n) / Fact($n - $r), "\n"; print FallingFact($n, $r), "\n"; # 重複順列 (異なる 10 個のものから重複を許して 5 個取ってできる順列の総数) $n = 10; $r = 5; print $n ** $r, "\n"; # 組合せ sub Comb { my ($n, $r) = @_; if ($r == 0 || $r == $n) { 1; } elsif ($r == 1) { $n; } else { Comb($n - 1, $r - 1) + Comb($n - 1, $r); } } # 組合せ (異なる 10 個のものから 5 個取ってできる組合せの総数) $n = 10; $r = 5; print Comb($n, $r), "\n"; # 組合せ sub Comb { my ($n, $r) = @_; if ($r == 0 || $r == $n) { 1; } elsif ($r == 1) { $n; } else { Comb($n - 1, $r - 1) + Comb($n - 1, $r); } } # 重複組合せ (異なる 10 個のものから重複を許して 5 個とる組合せの総数) $n = 10; $r = 5; print Comb($n + $r - 1, $r), "\n"; use Math::Trig qw'deg2rad tan'; # 自作の正弦関数 sub mySin { my ($x, $n, $nega, $numerator, $denominator, $y) = @_; $m = 2 * $n; $denominator = $denominator * ($m + 1) * $m; $numerator = $numerator * $x * $x; $a = $numerator / $denominator; # 十分な精度になったら処理を抜ける if ($a <= 0.00000000001) { $y; } else { $y + mySin($x, ++$n, !$nega, $numerator, $denominator, $nega ? $a : -$a); } } for $i (0..24) { $degree = $i * 15; if ($degree % 30 == 0 || $degree % 45 == 0) { $radian = deg2rad($degree); # 自作の正弦関数 $d1 = mySin($radian, 1, 0, $radian, 1.0, $radian); # 標準の正弦関数 $d2 = sin($radian); # 標準関数との差異 printf("%3d : %13.10f - %13.10f = %13.10f\n", $degree, $d1, $d2, $d1 - $d2); } } use Math::Trig qw'deg2rad tan'; # 自作の余弦関数 sub myCos { my ($x, $n, $nega, $numerator, $denominator, $y) = @_; $m = 2 * $n; $denominator = $denominator * $m * ($m - 1); $numerator = $numerator * $x * $x; $a = $numerator / $denominator; # 十分な精度になったら処理を抜ける if ($a <= 0.00000000001) { $y; } else { $y + myCos($x, ++$n, !$nega, $numerator, $denominator, $nega ? $a : -$a); } } for $i (0..24) { $degree = $i * 15; if ($degree % 30 == 0 || $degree % 45 == 0) { $radian = deg2rad($degree); # 自作の余弦関数 $d1 = myCos($radian, 1, 0, 1.0, 1.0, 1.0); # 標準の余弦関数 $d2 = cos($radian); # 標準関数との差異 printf("%3d : %13.10f - %13.10f = %13.10f\n", $degree, $d1, $d2, $d1 - $d2); } } use Math::Trig qw'deg2rad tan'; # 自作の正接関数 sub myTan { my ($x, $x2, $n, $t) = @_; $t = $x2 / ($n - $t); $n -= 2; if ($n <= 1) { $x / (1 - $t); } else { myTan($x, $x2, $n, $t); } } for $i (0..12) { if (($i * 15) % 180 != 0) { $degree = $i * 15 - 90; $radian = deg2rad($degree); $x2 = $radian * $radian; # 自作の正接関数 $d1 = myTan($radian, $x2, 15, 0.0); # 15:必要な精度が得られる十分大きな奇数 # 標準の正接関数 $d2 = tan($radian); # 標準関数との差異 printf("%3d : %13.10f - %13.10f = %13.10f\n", $degree, $d1, $d2, $d1 - $d2); } } # 自作の指数関数 sub myExp { my ($x, $n, $numerator, $denominator, $y) = @_; $denominator = $denominator * $n; $numerator = $numerator * $x; $a = $numerator / $denominator; # 十分な精度になったら処理を抜ける if (abs($a) <= 0.00000000001) { $y; } else { $y + myExp($x, ++$n, $numerator, $denominator, $a); } } for $i (0..20) { $x = ($i - 10) / 4.0; # 標準の指数関数 $d1 = exp($x); # 自作の指数関数 $d2 = myExp($x, 1, 1.0, 1.0, 1.0); # 標準関数との差異 printf("%5.2f : %13.10f - %13.10f = %13.10f\n", $x, $d1, $d2, $d1 - $d2); } # 自作の指数関数 sub myExp { my ($x, $x2, $n, $t) = @_; $t = $x2 / ($n + $t); $n -= 4; if ($n < 6) { 1 + ((2 * $x) / (2 - $x + $t)); } else { myExp($x, $x2, $n, $t); } } for $i (0..20) { $x = ($i - 10) / 4.0; # 標準の指数関数 $d1 = exp($x); # 自作の指数関数 $x2 = $x * $x; $d2 = myExp($x, $x2, 30, 0.0); # 30:必要な精度が得られるよう, 6から始めて4ずつ増加させる # 標準関数との差異 printf("%5.2f : %13.10f - %13.10f = %13.10f\n", $x, $d1, $d2, $d1 - $d2); } # 自作の対数関数 sub myLog { my ($x2, $numerator, $denominator, $y) = @_; $denominator = $denominator + 2; $numerator = $numerator * $x2 * $x2; $a = $numerator / $denominator; # 十分な精度になったら処理を抜ける if (abs($a) <= 0.00000000001) { $y; } else { $y + myLog($x2, $numerator, $denominator, $a); } } for $i (1..20) { $x = $i / 5.0; # 標準の対数関数 $d1 = log($x); # 自作の対数関数 $x2 = ($x - 1) / ($x + 1); $d2 = 2 * myLog($x2, $x2, 1.0, $x2); # 標準関数との差異 printf("%5.2f : %13.10f - %13.10f = %13.10f\n", $x, $d1, $d2, $d1 - $d2); } # 自作の対数関数 sub myLog { my ($x, $n, $t) = @_; $n2 = $n; $x2 = $x; if ($n > 3) { if ($n % 2 == 0) { $n2 = 2; } $x2 = $x * int($n / 2); } $t = $x2 / ($n2 + $t); if ($n <= 2) { $x / (1 + $t); } else { myLog($x, --$n, $t); } } for $i (1..20) { $x = $i / 5.0; # 標準の対数関数 $d1 = log($x); # 自作の対数関数 $d2 = myLog($x - 1, 27, 0.0); # 27:必要な精度が得られる十分大きな奇数 # 標準関数との差異 printf("%5.2f : %13.10f - %13.10f = %13.10f\n", $x, $d1, $d2, $d1 - $d2); } use Math::Trig; # 自作の双曲線正弦関数 sub mySinh { my ($x, $n, $numerator, $denominator, $y) = @_; $m = 2 * $n; $denominator = $denominator * ($m + 1) * $m; $numerator = $numerator * $x * $x; $a = $numerator / $denominator; # 十分な精度になったら処理を抜ける if (abs($a) <= 0.00000000001) { $y; } else { $y + mySinh($x, ++$n, $numerator, $denominator, $a); } } for $i (0..20) { $x = $i - 10; # 自作の双曲線正弦関数 $d1 = mySinh($x, 1, $x, 1.0, $x); # 標準の双曲線正弦関数 $d2 = sinh($x); # 標準関数との差異 printf("%3d : %17.10f - %17.10f = %13.10f\n", $x, $d1, $d2, $d1 - $d2); } use Math::Trig; # 自作の双曲線余弦関数 sub myCosh { my ($x, $n, $numerator, $denominator, $y) = @_; $m = 2 * $n; $denominator = $denominator * $m * ($m - 1); $numerator = $numerator * $x * $x; $a = $numerator / $denominator; # 十分な精度になったら処理を抜ける if (abs($a) <= 0.00000000001) { $y; } else { $y + myCosh($x, ++$n, $numerator, $denominator, $a); } } for $i (0..20) { $x = $i - 10; # 自作の双曲線余弦関数 $d1 = myCosh($x, 1, 1.0, 1.0, 1.0); # 標準の双曲線余弦関数 $d2 = cosh($x); # 標準関数との差異 printf("%3d : %17.10f - %17.10f = %13.10f\n", $x, $d1, $d2, $d1 - $d2); } use Math::Trig 'pi'; my $a = 0; my $b = 1; # 台形則で積分 my $n = 2; for $j (1..10) { my $h = ($b - $a) / $n; my $s = 0; my $x = $a; for $i (1..($n - 1)) { $x += $h; $s += f($x); } $s = $h * ((f($a) + f($b)) / 2 + $s); $n *= 2; # 結果を π と比較 printf("%2d : %13.10f, %13.10f\n", $j, $s, $s - pi); } sub f { my ($x) = @_; 4 / (1 + $x * $x); } use Math::Trig 'pi'; my $a = 0; my $b = 1; # 中点則で積分 my $n = 2; for $j (1..10) { my $h = ($b - $a) / $n; my $s = 0; my $x = $a + ($h / 2); for $i (1..$n) { $s += f($x); $x += $h; } $s *= $h; $n *= 2; # 結果を π と比較 printf("%2d : %13.10f, %13.10f\n", $j, $s, $s - pi); } sub f { my ($x) = @_; 4 / (1 + $x * $x); } use Math::Trig 'pi'; my $a = 0; my $b = 1; # Simpson則で積分 my $n = 2; for $j (1..5) { my $h = ($b - $a) / $n; my $s2 = 0; my $s4 = 0; my $x = $a + $h; for $i (1..($n / 2)) { $s4 += f($x); $x += $h; $s2 += f($x); $x += $h; } $s2 = ($s2 - f($b)) * 2 + f($a) + f($b); $s4 *= 4; my $s = ($s2 + $s4) * $h / 3; $n *= 2; # 結果を π と比較 printf("%2d : %13.10f, %13.10f\n", $j, $s, $s - pi); } sub f { my ($x) = @_; 4 / (1 + $x * $x); } use Math::Trig 'pi'; my $a = 0; my $b = 1; my @t = (); # 台形則で積分 my $n = 2; for $i (1..6) { my $h = ($b - $a) / $n; my $s = 0; my $x = $a; for $j (1..($n - 1)) { $x += $h; $s += f($x); } # 結果を保存 $t[$i][1] = $h * ((f($a) + f($b)) / 2 + $s); $n *= 2; } # Richardsonの補外法 $n = 4; for $j (2..6) { for $i ($j..6) { $t[$i][$j] = $t[$i][$j - 1] + ($t[$i][$j - 1] - $t[$i - 1][$j - 1]) / ($n - 1); if ($i == $j) { # 結果を π と比較 printf("%2d : %13.10f, %13.10f\n", $j, $t[$i][$j], $t[$i][$j] - pi); } } $n *= 4; } sub f { my ($x) = @_; 4 / (1 + $x * $x); } # データ点の数 - 1 use constant N => 6; my @x = (); my @y = (); # 1.5刻みで -4.5〜4.5 まで, 7点だけ値をセット for $i (0..N) { my $d = $i * 1.5 - 4.5; $x[$i] = $d; $y[$i] = f($d); } # 0.5刻みで 与えられていない値を補間 for $i (0..18) { my $d = $i * 0.5 - 4.5; my $d1 = f($d); my $d2 = lagrange($d, \@x, \@y); # 元の関数と比較 printf("%5.2f\t%8.5f\t%8.5f\t%8.5f\n", $d, $d1, $d2, $d1 - $d2); } # 元の関数 sub f { my ($x) = @_; $x - ($x ** 3) / (3 * 2) + ($x ** 5) / (5 * 4 * 3 * 2); } # Lagrange (ラグランジュ) 補間 sub lagrange { my ($d, $x, $y) = @_; my $sum = 0; for $i (0..N) { my $prod = $$y[$i]; for $j (0..N) { if ($j != $i) { $prod *= ($d - $$x[$j]) / ($$x[$i] - $$x[$j]); } } $sum += $prod; } $sum; } # データ点の数 - 1 use constant N => 6; my @x = (); my @y = (); # 1.5刻みで -4.5〜4.5 まで, 7点だけ値をセット for $i (0..N) { my $d = $i * 1.5 - 4.5; $x[$i] = $d; $y[$i] = f($d); } # 0.5刻みで 与えられていない値を補間 for $i (0..18) { my $d = $i * 0.5 - 4.5; my $d1 = f($d); my $d2 = neville($d, \@x, \@y); # 元の関数と比較 printf("%5.2f\t%8.5f\t%8.5f\t%8.5f\n", $d, $d1, $d2, $d1 - $d2); } # 元の関数 sub f { my ($x) = @_; $x - ($x ** 3) / (3 * 2) + ($x ** 5) / (5 * 4 * 3 * 2); } # Neville (ネヴィル) 補間 sub neville { my ($d, $x, $y) = @_; my @w = (); for $i (0..N) { $w[0][$i] = $$y[$i]; } for $j (1..N) { for $i (0..(N - $j)) { $w[$j][$i] = $w[$j-1][$i+1] + ($w[$j-1][$i+1] - $w[$j-1][$i]) * ($d - $$x[$i+$j]) / ($$x[$i+$j] - $$x[$i]); } } $w[N][0]; } # データ点の数 - 1 use constant N => 6; my @x = (); my @y = (); # 1.5刻みで -4.5〜4.5 まで, 7点だけ値をセット for $i (0..N) { my $d1 = $i * 1.5 - 4.5; $x[$i] = $d1; $y[$i] = f($d1); } # 差分商の表を作る my @d = (); for $j (0..N) { $d[0][$j] = $y[$j]; } for $i (1..N) { for $j (0..(N - $i)) { $d[$i][$j] = ($d[$i-1][$j+1] - $d[$i-1][$j]) / ($x[$j+$i] - $x[$j]); } } # n階差分商 my @a = (); for $j (0..N) { $a[$j] = $d[$j][0]; } # 0.5刻みで 与えられていない値を補間 for $i (0..18) { my $d1 = $i * 0.5 - 4.5; my $d2 = f($d1); my $d3 = newton($d1, \@x, \@a); # 元の関数と比較 printf("%5.2f\t%8.5f\t%8.5f\t%8.5f\n", $d1, $d2, $d3, $d2 - $d3); } # 元の関数 sub f { my ($x) = @_; $x - ($x ** 3) / (3 * 2) + ($x ** 5) / (5 * 4 * 3 * 2); } # Newton (ニュートン) 補間 sub newton { my ($d, $x, $a) = @_; my $sum = $$a[0]; for $i (1..N) { my $prod = $$a[$i]; for $j (0..($i - 1)) { $prod *= ($d - $$x[$j]); } $sum += $prod; } $sum; } # データ点の数 - 1 use constant N => 6; use constant Nx2 => 13; my @x = (); my @y = (); my @yd = (); # 1.5刻みで -4.5〜4.5 まで, 7点だけ値をセット for $i (0..N) { my $d1 = $i * 1.5 - 4.5; $x[$i] = $d1; $y[$i] = f($d1); $yd[$i] = fd($d1); } # 差分商の表を作る my @z = (); my @d = (); for $i (0..Nx2) { $j = int($i / 2); $z[$i] = $x[$j]; $d[0][$i] = $y[$j]; } for $i (1..Nx2) { for $j (0..(Nx2 - $i)) { if ($i == 1 && $j % 2 == 0) { $d[$i][$j] = $yd[int($j / 2)]; } else { $d[$i][$j] = ($d[$i-1][$j+1] - $d[$i-1][$j]) / ($z[$j+$i] - $z[$j]); } } } # n階差分商 my @a = (); for $j (0..Nx2) { $a[$j] = $d[$j][0]; } # 0.5刻みで 与えられていない値を補間 for $i (0..18) { my $d1 = $i * 0.5 - 4.5; my $d2 = f($d1); my $d3 = hermite($d1, \@z, \@a); # 元の関数と比較 printf("%5.2f\t%8.5f\t%8.5f\t%8.5f\n", $d1, $d2, $d3, $d2 - $d3); } # 元の関数 sub f { my ($x) = @_; $x - ($x ** 3) / (3 * 2) + ($x ** 5) / (5 * 4 * 3 * 2); } # 導関数 sub fd { my ($x) = @_; 1 - ($x ** 2) / 2 + ($x ** 4) / (4 * 3 * 2); } # Hermite (エルミート) 補間 sub hermite { my ($d, $z, $a) = @_; my $sum = $$a[0]; for $i (1..Nx2) { my $prod = $$a[$i]; for $j (0..($i - 1)) { $prod *= ($d - $$z[$j]); } $sum += $prod; } $sum; } # データ点の数 - 1 use constant N => 6; my @x = (); my @y = (); # 1.5刻みで -4.5〜4.5 まで, 7点だけ値をセット for $i (0..N) { my $d1 = $i * 1.5 - 4.5; $x[$i] = $d1; $y[$i] = f($d1); } # 3項方程式の係数の表を作る my @a = (); my @b = (); my @c = (); my @d = (); for $i (1..(N - 1)) { $a[$i] = $x[$i] - $x[$i-1]; $b[$i] = 2.0 * ($x[$i+1] - $x[$i-1]); $c[$i] = $x[$i+1] - $x[$i]; $d[$i] = 6.0 * (($y[$i+1] - $y[$i]) / ($x[$i+1] - $x[$i]) - ($y[$i] - $y[$i-1]) / ($x[$i] - $x[$i-1])); } # 3項方程式を解く (ト−マス法) my @g = (); my @s = (); $g[1] = $b[1]; $s[1] = $d[1]; for $i (2..(N - 1)) { $g[$i] = $b[$i] - $a[$i] * $c[$i-1] / $g[$i-1]; $s[$i] = $d[$i] - $a[$i] * $s[$i-1] / $g[$i-1]; } my @z = (); $z[0] = 0; $z[N] = 0; $z[N-1] = $s[N-1] / $g[N-1]; for ($i = N - 2; $i >= 1; $i--) { $z[$i] = ($s[$i] - $c[$i] * $z[$i+1]) / $g[$i]; } # 0.5刻みで 与えられていない値を補間 for $i (0..18) { my $d1 = $i * 0.5 - 4.5; my $d2 = f($d1); my $d3 = spline($d1, \@x, \@y, \@z); # 元の関数と比較 printf("%5.2f\t%8.5f\t%8.5f\t%8.5f\n", $d1, $d2, $d3, $d2 - $d3); } # 元の関数 sub f { my ($x) = @_; $x - ($x ** 3) / (3 * 2) + ($x ** 5) / (5 * 4 * 3 * 2); } # Spline (スプライン) 補間 sub spline { my ($d, $x, $y, $z) = @_; # 補間関数値がどの区間にあるか my $k = -1; for $i (1..N) { if ($d <= $$x[$i]) { $k = $i - 1; last; } } if ($k < 0) { $k = N; } $d1 = $$x[$k+1] - $d; $d2 = $d - $$x[$k]; $d3 = $$x[$k+1] - $$x[$k]; ($$z[$k] * ($d1 ** 3) + $$z[$k+1] * ($d2 ** 3)) / (6.0 * $d3) + ($$y[$k] / $d3 - $$z[$k] * $d3 / 6.0) * $d1 + ($$y[$k+1] / $d3 - $$z[$k+1] * $d3 / 6.0) * $d2; } use Math::Trig 'pi'; # 重力加速度 my $g = -9.8; # 空気抵抗係数 my $k = -0.01; # 時間間隔(秒) my $h = 0.01; # 角度 my $degree = 45; my $radian = $degree * pi / 180.0; # 初速 250 km/h -> 秒速に変換 my $v = int(250 * 1000 / 3600); # 水平方向の速度 my @vx = (); $vx[0] = $v * cos($radian); # 鉛直方向の速度 my @vy = (); $vy[0] = $v * sin($radian); # 経過秒数 my $t = 0.0; # 位置 my $x = 0.0; my $y = 0.0; # Euler法 for (my $i = 1; $y >= 0.0; $i++) { # 経過秒数 $t = $i * $h; # 位置 $x += $h * $vx[0]; $y += $h * $vy[0]; printf("%4.2f\t%8.5f\t%9.5f\t%9.5f\t%8.5f\n", $t, $vx[0], $vy[0], $x, $y); # 速度 $vx[1] = $vx[0] + $h * fx($vx[0], $vy[0]); $vy[1] = $vy[0] + $h * fy($vx[0], $vy[0]); $vx[0] = $vx[1]; $vy[0] = $vy[1]; } # 空気抵抗による水平方向の減速分 sub fx { my ($vx, $vy) = @_; $k * sqrt($vx * $vx + $vy * $vy) * $vx; } # 重力と空気抵抗による鉛直方向の減速分 sub fy { my ($vx, $vy) = @_; $g + ($k * sqrt($vx * $vx + $vy * $vy) * $vy); } use Math::Trig 'pi'; # 重力加速度 my $g = -9.8; # 空気抵抗係数 my $k = -0.01; # 時間間隔(秒) my $h = 0.01; # 角度 my $degree = 45; my $radian = $degree * pi / 180.0; # 初速 250 km/h -> 秒速に変換 my $v = int(250 * 1000 / 3600); # 水平方向の速度 my @vx = (); $vx[0] = $v * cos($radian); # 鉛直方向の速度 my @vy = (); $vy[0] = $v * sin($radian); # 経過秒数 my $t = 0.0; # 位置 my @x = (); $x[0] = 0.0; my @y = (); $y[0] = 0.0; # Heun法 for (my $i = 1; $y[0] >= 0.0; $i++) { # 経過秒数 $t = $i * $h; # 位置・速度 $x[1] = $x[0] + $h * $vx[0]; $y[1] = $y[0] + $h * $vy[0]; $vx[1] = $vx[0] + $h * fx($vx[0], $vy[0]); $vy[1] = $vy[0] + $h * fy($vx[0], $vy[0]); $x[2] = $x[0] + $h * ( $vx[0] + $vx[1] ) / 2; $y[2] = $y[0] + $h * ( $vy[0] + $vy[1] ) / 2; $vx[2] = $vx[0] + $h * (fx($vx[0], $vy[0]) + fx($vx[1], $vy[1])) / 2; $vy[2] = $vy[0] + $h * (fy($vx[0], $vy[0]) + fy($vx[1], $vy[1])) / 2; $x[0] = $x[2]; $y[0] = $y[2]; $vx[0] = $vx[2]; $vy[0] = $vy[2]; printf("%4.2f\t%8.5f\t%9.5f\t%9.5f\t%8.5f\n", $t, $vx[0], $vy[0], $x[0], $y[0]); } # 空気抵抗による水平方向の減速分 sub fx { my ($vx, $vy) = @_; $k * sqrt($vx * $vx + $vy * $vy) * $vx; } # 重力と空気抵抗による鉛直方向の減速分 sub fy { my ($vx, $vy) = @_; $g + ($k * sqrt($vx * $vx + $vy * $vy) * $vy); } use Math::Trig 'pi'; # 重力加速度 my $g = -9.8; # 空気抵抗係数 my $k = -0.01; # 時間間隔(秒) my $h = 0.01; # 角度 my $degree = 45; my $radian = $degree * pi / 180.0; # 初速 250 km/h -> 秒速に変換 my $v = int(250 * 1000 / 3600); # 水平方向の速度 my @vx = (); $vx[0] = $v * cos($radian); # 鉛直方向の速度 my @vy = (); $vy[0] = $v * sin($radian); # 経過秒数 my $t = 0.0; # 位置 my @x = (); $x[0] = 0.0; my @y = (); $y[0] = 0.0; # 中点法 for (my $i = 1; $y[0] >= 0.0; $i++) { # 経過秒数 $t = $i * $h; # 位置・速度 $vx[1] = $h * fx($vx[0], $vy[0]); $vy[1] = $h * fy($vx[0], $vy[0]); my $wx = $vx[0] + $vx[1] / 2; my $wy = $vy[0] + $vy[1] / 2; $vx[0] = $vx[0] + $h * fx($wx, $wy); $vy[0] = $vy[0] + $h * fy($wx, $wy); $x[0] = $x[0] + $h * $wx; $y[0] = $y[0] + $h * $wy; printf("%4.2f\t%8.5f\t%9.5f\t%9.5f\t%9.5f\n", $t, $vx[0], $vy[0], $x[0], $y[0]); } # 空気抵抗による水平方向の減速分 sub fx { my ($vx, $vy) = @_; $k * sqrt($vx * $vx + $vy * $vy) * $vx; } # 重力と空気抵抗による鉛直方向の減速分 sub fy { my ($vx, $vy) = @_; $g + ($k * sqrt($vx * $vx + $vy * $vy) * $vy); } use Math::Trig 'pi'; # 重力加速度 my $g = -9.8; # 空気抵抗係数 my $k = -0.01; # 時間間隔(秒) my $h = 0.01; # 角度 my $degree = 45; my $radian = $degree * pi / 180.0; # 初速 250 km/h -> 秒速に変換 my $v = int(250 * 1000 / 3600); # 水平方向の速度 my @vx = (); $vx[0] = $v * cos($radian); # 鉛直方向の速度 my @vy = (); $vy[0] = $v * sin($radian); # 経過秒数 my $t = 0.0; # 位置 my @x = (); $x[0] = 0.0; my @y = (); $y[0] = 0.0; # Runge-Kutta法 for (my $i = 1; $y[0] >= 0.0; $i++) { # 経過秒数 $t = $i * $h; # 位置・速度 $x[1] = $h * $vx[0]; $y[1] = $h * $vy[0]; $vx[1] = $h * fx($vx[0], $vy[0]); $vy[1] = $h * fy($vx[0], $vy[0]); my $wx = $vx[0] + $vx[1] / 2; my $wy = $vy[0] + $vy[1] / 2; $x[2] = $h * $wx; $y[2] = $h * $wy; $vx[2] = $h * fx($wx, $wy); $vy[2] = $h * fy($wx, $wy); $wx = $vx[0] + $vx[2] / 2; $wy = $vy[0] + $vy[2] / 2; $x[3] = $h * $wx; $y[3] = $h * $wy; $vx[3] = $h * fx($wx, $wy); $vy[3] = $h * fy($wx, $wy); $wx = $vx[0] + $vx[3]; $wy = $vy[0] + $vy[3]; $x[4] = $h * $wx; $y[4] = $h * $wy; $vx[4] = $h * fx($wx, $wy); $vy[4] = $h * fy($wx, $wy); $x[0] += ( $x[1] + $x[2] * 2 + $x[3] * 2 + $x[4]) / 6; $y[0] += ( $y[1] + $y[2] * 2 + $y[3] * 2 + $y[4]) / 6; $vx[0] += ($vx[1] + $vx[2] * 2 + $vx[3] * 2 + $vx[4]) / 6; $vy[0] += ($vy[1] + $vy[2] * 2 + $vy[3] * 2 + $vy[4]) / 6; printf("%4.2f\t%8.5f\t%9.5f\t%9.5f\t%9.5f\n", $t, $vx[0], $vy[0], $x[0], $y[0]); } # 空気抵抗による水平方向の減速分 sub fx { my ($vx, $vy) = @_; $k * sqrt($vx * $vx + $vy * $vy) * $vx; } # 重力と空気抵抗による鉛直方向の減速分 sub fy { my ($vx, $vy) = @_; $g + ($k * sqrt($vx * $vx + $vy * $vy) * $vy); } use Math::Trig 'pi'; # 重力加速度 my $g = -9.8; # 空気抵抗係数 my $k = -0.01; # 時間間隔(秒) my $h = 0.01; # 角度 my $degree = 45; my $radian = $degree * pi / 180.0; # 初速 250 km/h -> 秒速に変換 my $v = int(250 * 1000 / 3600); # 水平方向の速度 my @vx = (); $vx[0] = $v * cos($radian); # 鉛直方向の速度 my @vy = (); $vy[0] = $v * sin($radian); # 経過秒数 my $t = 0.0; # 位置 my @x = (); $x[0] = 0.0; my @y = (); $y[0] = 0.0; # Runge-Kutta-Gill法 for (my $i = 1; $y[0] >= 0.0; $i++) { # 経過秒数 $t = $i * $h; # 位置・速度 $x[1] = $h * $vx[0]; $y[1] = $h * $vy[0]; $vx[1] = $h * fx($vx[0], $vy[0]); $vy[1] = $h * fy($vx[0], $vy[0]); my $wx = $vx[0] + $vx[1] / 2; my $wy = $vy[0] + $vy[1] / 2; $x[2] = $h * $wx; $y[2] = $h * $wy; $vx[2] = $h * fx($wx, $wy); $vy[2] = $h * fy($wx, $wy); $wx = $vx[0] + $vx[1] * ((sqrt(2.0) - 1) / 2) + $vx[2] * (1 - 1 / sqrt(2.0)); $wy = $vy[0] + $vy[1] * ((sqrt(2.0) - 1) / 2) + $vy[2] * (1 - 1 / sqrt(2.0)); $x[3] = $h * $wx; $y[3] = $h * $wy; $vx[3] = $h * fx($wx, $wy); $vy[3] = $h * fy($wx, $wy); $wx = $vx[0] - $vx[2] / sqrt(2.0) + $vx[3] * (1 + 1 / sqrt(2.0)); $wy = $vy[0] - $vy[2] / sqrt(2.0) + $vy[3] * (1 + 1 / sqrt(2.0)); $x[4] = $h * $wx; $y[4] = $h * $wy; $vx[4] = $h * fx($wx, $wy); $vy[4] = $h * fy($wx, $wy); $x[0] += ( $x[1] + $x[2] * (2 - sqrt(2.0)) + $x[3] * (2 + sqrt(2.0)) + $x[4]) / 6; $y[0] += ( $y[1] + $y[2] * (2 - sqrt(2.0)) + $y[3] * (2 + sqrt(2.0)) + $y[4]) / 6; $vx[0] += ($vx[1] + $vx[2] * (2 - sqrt(2.0)) + $vx[3] * (2 + sqrt(2.0)) + $vx[4]) / 6; $vy[0] += ($vy[1] + $vy[2] * (2 - sqrt(2.0)) + $vy[3] * (2 + sqrt(2.0)) + $vy[4]) / 6; printf("%4.2f\t%8.5f\t%9.5f\t%9.5f\t%9.5f\n", $t, $vx[0], $vy[0], $x[0], $y[0]); } # 空気抵抗による水平方向の減速分 sub fx { my ($vx, $vy) = @_; $k * sqrt($vx * $vx + $vy * $vy) * $vx; } # 重力と空気抵抗による鉛直方向の減速分 sub fy { my ($vx, $vy) = @_; $g + ($k * sqrt($vx * $vx + $vy * $vy) * $vy); } my $a = 1; my $b = 2; printf("%12.10f\n", bisection($a, $b)); sub bisection { my ($a, $b) = @_; my $c; while (1) { # 区間 (a, b) の中点 c = (a + b) / 2 $c = ($a + $b) / 2; printf("%12.10f\t%13.10f\n", $c, $c - sqrt(2)); my $fc = f($c); if (abs($fc) < 0.0000000001) { last; } if ($fc < 0) { # f(c) < 0 であれば, 解は区間 (c, b) の中に存在 $a = $c; } else { # f(c) > 0 であれば, 解は区間 (a, c) の中に存在 $b = $c; } } $c; } sub f { my ($x) = @_; $x * $x - 2; } my $a = 1; my $b = 2; printf("%12.10f\n", falseposition($a, $b)); sub falseposition { my ($a, $b) = @_; my $c; while (1) { # 点 (a,f(a)) と 点 (b,f(b)) を結ぶ直線と x軸の交点 $c = ($a * f($b) - $b * f($a)) / (f($b) - f($a)); printf("%12.10f\t%13.10f\n", $c, $c - sqrt(2)); my $fc = f($c); if (abs($fc) < 0.0000000001) { last; } if ($fc < 0) { # f(c) < 0 であれば, 解は区間 (c, b) の中に存在 $a = $c; } else { # f(c) > 0 であれば, 解は区間 (a, c) の中に存在 $b = $c; } } $c; } sub f { my ($x) = @_; $x * $x - 2; } my $x = 1; printf("%12.10f\n", iterative($x)); sub iterative { my ($x0) = @_; my $x1; while (1) { $x1 = g($x0); printf("%12.10f\t%13.10f\n", $x1, $x1 - sqrt(2)); if (abs($x1 - $x0) < 0.0000000001) { last; } $x0 = $x1; } $x1; } sub g { my ($x) = @_; ($x / 2) + (1 / $x); } my $x = 2; printf("%12.10f\n", newton($x)); sub newton { my ($x0) = @_; my $x1; while (1) { $x1 = $x0 - (f0($x0) / f1($x0)); printf("%12.10f\t%13.10f\n", $x1, $x1 - sqrt(2)); if (abs($x1 - $x0) < 0.0000000001) { last; } $x0 = $x1; } $x1; } sub f0 { my ($x) = @_; $x * $x - 2; } sub f1 { my ($x) = @_; 2 * $x; } my $x = 2; printf("%12.10f\n", bailey($x)); sub bailey { my ($x0) = @_; my $x1; while (1) { $x1 = $x0 - (f0($x0) / (f1($x0) - (f0($x0) * f2($x0) / (2 * f1($x0))))); printf("%12.10f\t%13.10f\n", $x1, $x1 - sqrt(2)); if (abs($x1 - $x0) < 0.0000000001) { last; } $x0 = $x1; } $x1; } sub f0 { my ($x) = @_; $x * $x - 2; } sub f1 { my ($x) = @_; 2 * $x; } sub f2 { my ($x) = @_; 2; } my $x0 = 1; my $x1 = 2; printf("%12.10f\n", secant($x0, $x1)); sub secant { my ($x0, $x1) = @_; my $x2; while (1) { $x2 = $x1 - f($x1) * ($x1 - $x0) / (f($x1) - f($x0)); printf("%12.10f\t%13.10f\n", $x2, $x2 - sqrt(2)); if (abs($x2 - $x1) < 0.0000000001) { last; } $x0 = $x1; $x1 = $x2; } $x2; } sub f { my ($x) = @_; $x * $x - 2; } use constant N => 3; my @a = ([9,2,1,1],[2,8,-2,1],[-1,-2,7,-2],[1,-1,-2,6]); my @b = (20,16,8,17); my @c = (0,0,0,0); # ヤコビの反復法 jacobi(\@a, \@b, \@c); print "解\n"; for $i (0..N) { printf("%14.10f\t", $c[$i]); } print "\n"; # ヤコビの反復法 sub jacobi { my ($a, $b, $x0) = @_; while (1) { my @x1 = (); my $finish = 1; for $i (0..N) { $x1[$i] = 0; for $j (0..N) { if ($j != $i) { $x1[$i] += $a[$i][$j] * $$x0[$j]; } } $x1[$i] = ($b[$i] - $x1[$i]) / $a[$i][$i]; if (abs($x1[$i] - $$x0[$i]) > 0.0000000001) {$finish = 0;} } for $i (0..N) { $$x0[$i] = $x1[$i]; printf("%14.10f\t", $$x0[$i]); } print "\n"; last if ($finish); } } use constant N => 3; my @a = ([9,2,1,1],[2,8,-2,1],[-1,-2,7,-2],[1,-1,-2,6]); my @b = (20,16,8,17); my @c = (0,0,0,0); # ガウス・ザイデル法 gauss(\@a, \@b, \@c); print "解\n"; for $i (0..N) { printf("%14.10f\t", $c[$i]); } print "\n"; # ガウス・ザイデル法 sub gauss { my ($a, $b, $x0) = @_; while (1) { my $finish = 1; for $i (0..N) { my $x1 = 0; for $j (0..N) { if ($j != $i) { $x1 += $a[$i][$j] * $$x0[$j]; } } $x1 = ($b[$i] - $x1) / $a[$i][$i]; if (abs($x1 - $$x0[$i]) > 0.0000000001) {$finish = 0;} $$x0[$i] = $x1; } for $i (0..N) { printf("%14.10f\t", $$x0[$i]); } print "\n"; last if ($finish); } } use constant N => 3; my @a = ([-1,-2,7,-2],[1,-1,-2,6],[9,2,1,1],[2,8,-2,1]); my @b = (8,17,20,16); # ピボット選択 pivoting(\@a,\@b); print "ピボット選択後\n"; disp_progress(\@a,\@b); # 前進消去 forward_elimination(\@a,\@b); print "前進消去後\n"; disp_progress(\@a,\@b); # 後退代入 backward_substitution(\@a,\@b); print "解\n"; for $i (0..N) { printf("%14.10f\t", $b[$i]); } print "\n"; # 前進消去 sub forward_elimination { my ($a, $b) = @_; for $pivot (0..(N - 1)) { for $row (($pivot + 1)..N) { my $s = $a[$row][$pivot] / $a[$pivot][$pivot]; for $col ($pivot..N) { $a[$row][$col] -= $a[$pivot][$col] * $s; } $$b[$row] -= $$b[$pivot] * $s; } } } # 後退代入 sub backward_substitution { my ($a, $b) = @_; for ($row = N; $row >= 0; $row--) { for ($col = N; $col > $row; $col--) { $$b[$row] -= $a[$row][$col] * $$b[$col]; } $$b[$row] /= $a[$row][$row]; } } # ピボット選択 sub pivoting { my ($a, $b) = @_; for $pivot (0..N) { # 各列で 一番値が大きい行を 探す my $max_row = $pivot; my $max_val = 0; for $row ($pivot..N) { if (abs($a[$row][$pivot]) > $max_val) { # 一番値が大きい行 $max_val = abs($a[$row][$pivot]); $max_row = $row; } } # 一番値が大きい行と入れ替え if ($max_row != $pivot) { my $tmp; for $col (0..N) { $tmp = $a[$max_row][$col]; $a[$max_row][$col] = $a[$pivot][$col]; $a[$pivot][$col] = $tmp; } $tmp = $b[$max_row]; $b[$max_row] = $b[$pivot]; $b[$pivot] = $tmp; } } } # 状態を確認 sub disp_progress { my ($a, $b) = @_; for $i (0..N) { for $j (0..N) { printf("%14.10f\t", $a[$i][$j]); } printf("%14.10f\n", $b[$i]); } print "\n"; } use constant N => 3; my @a = ([-1,-2,7,-2],[1,-1,-2,6],[9,2,1,1],[2,8,-2,1]); my @b = (8,17,20,16); # ピボット選択 pivoting(\@a,\@b); print "ピボット選択後\n"; disp_progress(\@a,\@b); # 前進消去 forward_elimination(\@a,\@b); print "前進消去後\n"; disp_progress(\@a,\@b); # 後退代入 backward_substitution(\@a,\@b); print "解\n"; for $i (0..N) { printf("%14.10f\t", $b[$i]); } print "\n"; # 前進消去 sub forward_elimination { my ($a, $b) = @_; for $pivot (0..(N - 1)) { for $row (($pivot + 1)..N) { my $s = $$a[$row][$pivot] / $$a[$pivot][$pivot]; for $col ($pivot..N) { $$a[$row][$col] -= $$a[$pivot][$col] * $s; } $$b[$row] -= $$b[$pivot] * $s; } } } # 後退代入 sub backward_substitution { my ($a, $b) = @_; for ($row = N; $row >= 0; $row--) { for ($col = N; $col > $row; $col--) { $$b[$row] -=$$a[$row][$col] * $$b[$col]; } $$b[$row] /= $a[$row][$row]; } } # ピボット選択 sub pivoting { my ($a, $b) = @_; for $pivot (0..N) { # 各列で 一番値が大きい行を 探す my $max_row = $pivot; my $max_val = 0; for $row ($pivot..N) { if (abs($$a[$row][$pivot]) > $max_val) { # 一番値が大きい行 $max_val = abs($$a[$row][$pivot]); $max_row = $row; } } # 一番値が大きい行と入れ替え if ($max_row != $pivot) { my $tmp; for $col (0..N) { $tmp = $$a[$max_row][$col]; $$a[$max_row][$col] = $$a[$pivot][$col]; $$a[$pivot][$col] = $tmp; } $tmp = $$b[$max_row]; $$b[$max_row] = $$b[$pivot]; $$b[$pivot] = $tmp; } } } # 状態を確認 sub disp_progress { my ($a, $b) = @_; for $i (0..N) { for $j (0..N) { printf("%14.10f\t", $a[$i][$j]); } printf("%14.10f\n", $b[$i]); } print "\n"; } use constant N => 3; my @a = ([-1,-2,7,-2],[1,-1,-2,6],[9,2,1,1],[2,8,-2,1]); my @b = (8,17,20,16); # ピボット選択 pivoting(\@a,\@b); print "ピボット選択後\n"; disp_progress(\@a,\@b); # 前進消去 forward_elimination(\@a,\@b); print "前進消去後\n"; disp_progress(\@a,\@b); # 後退代入 backward_substitution(\@a,\@b); print "解\n"; for $i (0..N) { printf("%14.10f\t", $b[$i]); } print "\n"; # 前進消去 sub forward_elimination { my ($a, $b) = @_; # 対角線上の係数を 1 にする for $pivot (0..N) { my $s = $$a[$pivot][$pivot]; for $col (0..N) { $$a[$pivot][$col] /= $s; } $$b[$pivot] /= $s; } print "対角線上の係数を 1 にする\n"; disp_progress($a,$b); # 対角行列にする for $pivot (0..N) { for $row (0..N) { next if ($row == $pivot); my $s = $$a[$row][$pivot] / $$a[$pivot][$pivot]; for $col ($pivot..N) { $$a[$row][$col] -= $$a[$pivot][$col] * $s; } $$b[$row] -= $$b[$pivot] * $s; } } } # 後退代入 sub backward_substitution { my ($a, $b) = @_; for $pivot (0..N) { $$b[$pivot] /= $$a[$pivot][$pivot]; } } # ピボット選択 sub pivoting { my ($a, $b) = @_; for $pivot (0..N) { # 各列で 一番値が大きい行を 探す my $max_row = $pivot; my $max_val = 0; for $row ($pivot..N) { if (abs($$a[$row][$pivot]) > $max_val) { # 一番値が大きい行 $max_val = abs($$a[$row][$pivot]); $max_row = $row; } } # 一番値が大きい行と入れ替え if ($max_row != $pivot) { my $tmp; for $col (0..N) { $tmp = $$a[$max_row][$col]; $$a[$max_row][$col] = $$a[$pivot][$col]; $$a[$pivot][$col] = $tmp; } $tmp = $$b[$max_row]; $$b[$max_row] = $$b[$pivot]; $$b[$pivot] = $tmp; } } } # 状態を確認 sub disp_progress { my ($a, $b) = @_; for $i (0..N) { for $j (0..N) { printf("%14.10f\t", $a[$i][$j]); } printf("%14.10f\n", $b[$i]); } print "\n"; } use constant N => 3; my @a = ([-1,-2,7,-2],[1,-1,-2,6],[9,2,1,1],[2,8,-2,1]); my @b = (8,17,20,16); # ピボット選択 pivoting(\@a,\@b); print "ピボット選択後\n"; disp_progress(\@a,\@b); # LU分解 my @x = (0,0,0,0); decomp(\@a,\@b,\@x); print "X\n"; for $i (0..N) { printf("%14.10f\t", $x[$i]); } print "\n"; # LU分解 sub decomp { my ($a, $b, $x) = @_; # 前進消去 forward_elimination(\@a,\@b); # 下三角行列を確認 print "L\n"; for $i (0..N) { for $j (0..N) { if ($i > $j) { printf("%14.10f\t", $a[$i][$j]); } elsif ($i == $j) { printf("%14.10f\t", 1.0); } else { printf("%14.10f\t", 0.0); } } print "\n"; } print "\n"; # 上三角行列を確認 print "U\n"; for $i (0..N) { for $j (0..N) { if ($i <= $j) { printf("%14.10f\t", $a[$i][$j]); } else { printf("%14.10f\t", 0.0); } } print "\n"; } print "\n"; # Ly=b から y を求める (前進代入) my @y = (0,0,0,0); forward_substitution(\@a,\@b,\@y); # y の 値 を確認 print "Y\n"; for $i (0..N) { printf("%14.10f\t", $y[$i]); } print "\n"; # Ux=y から x を求める (後退代入) backward_substitution(\@a,\@y,\@x); } # 前進消去 sub forward_elimination { my ($a, $b) = @_; for $pivot (0..(N - 1)) { for $row (($pivot + 1)..N) { my $s = $$a[$row][$pivot] / $$a[$pivot][$pivot]; for $col ($pivot..N) { $$a[$row][$col] -= $$a[$pivot][$col] * $s; # これが 上三角行列 } $$a[$row][$pivot] = $s; # これが 下三角行列 # $b[$row] -= $b[$pivot] * $s; # この値は変更しない } } } # Ly=b から y を求める (前進代入) sub forward_substitution { my ($a, $b, $y) = @_; for $row (0..N) { for $col (0..$row) { $b[$row] -= $a[$row][$col] * $$y[$col]; } $$y[$row] = $b[$row]; } } # Ux=y から x を求める (後退代入) sub backward_substitution { my ($a, $y, $x) = @_; for ($row = N; $row >= 0; $row--) { for ($col = N; $col > $row; $col--) { $$y[$row] -= $a[$row][$col] * $$x[$col]; } $$x[$row] = $$y[$row] / $a[$row][$row]; } } # ピボット選択 sub pivoting { my ($a, $b) = @_; for $pivot (0..N) { # 各列で 一番値が大きい行を 探す my $max_row = $pivot; my $max_val = 0; for $row ($pivot..N) { if (abs($$a[$row][$pivot]) > $max_val) { # 一番値が大きい行 $max_val = abs($$a[$row][$pivot]); $max_row = $row; } } # 一番値が大きい行と入れ替え if ($max_row != $pivot) { my $tmp; for $col (0..N) { $tmp = $$a[$max_row][$col]; $$a[$max_row][$col] = $$a[$pivot][$col]; $$a[$pivot][$col] = $tmp; } $tmp = $$b[$max_row]; $$b[$max_row] = $$b[$pivot]; $$b[$pivot] = $tmp; } } } # 状態を確認 sub disp_progress { my ($a, $b) = @_; for $i (0..N) { for $j (0..N) { printf("%14.10f\t", $a[$i][$j]); } printf("%14.10f\n", $b[$i]); } print "\n"; } use constant N => 3; my @a = ([5,2,3,4],[2,10,6,7],[3,6,15,9],[4,7,9,20]); my @b = (34,68,96,125); print "A\n"; disp_progress(\@a); # LL^T分解 my @x = (0,0,0,0); decomp(\@a,\@b,\@x); print "X\n"; for $i (0..N) { printf("%14.10f\t", $x[$i]); } print "\n"; # LL^T分解 sub decomp { my ($a, $b, $x) = @_; # 前進消去 forward_elimination(\@a,\@b); print "L と L^T\n"; for $i (0..N) { for $j (0..N) { if ($j <= $i) { printf("%14.10f\t", $a[$i][$j]); } else { printf("%14.10f\t", $a[$j][$i]); } } print "\n"; } print "\n"; # Ly=b から y を求める (前進代入) my @y = (0,0,0,0); forward_substitution(\@a,\@b,\@y); # y の 値 を確認 print "Y\n"; for $i (0..N) { printf("%14.10f\t", $y[$i]); } print "\n"; # Ux=y から x を求める (後退代入) backward_substitution(\@a,\@y,\@x); } # 前進消去 sub forward_elimination { my ($a, $b) = @_; for $pivot (0..N) { my $s = 0; for $col (0..($pivot-1)) { $s += $$a[$pivot][$col] * $$a[$pivot][$col]; } # ここで根号の中が負の値になると計算できない! $$a[$pivot][$pivot] = sqrt($$a[$pivot][$pivot] - $s); for $row (($pivot + 1)..N) { $s = 0; for $col (0..($pivot-1)) { $s += $$a[$row][$col] * $$a[$pivot][$col]; } $$a[$row][$pivot] = ($$a[$row][$pivot] - $s) / $$a[$pivot][$pivot]; } } } # Ly=b から y を求める (前進代入) sub forward_substitution { my ($a, $b, $y) = @_; for $row (0..N) { for $col (0..$row) { $b[$row] -= $a[$row][$col] * $$y[$col]; } $$y[$row] = $b[$row] / $a[$row][$row]; } } # Ux=y から x を求める (後退代入) sub backward_substitution { my ($a, $y, $x) = @_; for ($row = N; $row >= 0; $row--) { for ($col = N; $col > $row; $col--) { $$y[$row] -= $a[$col][$row] * $$x[$col]; } $$x[$row] = $$y[$row] / $a[$row][$row]; } } # 状態を確認 sub disp_progress { my ($a) = @_; for $i (0..N) { for $j (0..N) { printf("%14.10f\t", $a[$i][$j]); } print "\n"; } print "\n"; } use constant N => 3; my @a = ([5,2,3,4],[2,10,6,7],[3,6,15,9],[4,7,9,20]); my @b = (34,68,96,125); print "A\n"; disp_progress(\@a); # LDL^T分解 my @x = (0,0,0,0); decomp(\@a,\@b,\@x); print "X\n"; for $i (0..N) { printf("%14.10f\t", $x[$i]); } print "\n"; # LDL^T分解 sub decomp { my ($a, $b, $x) = @_; # 前進消去 forward_elimination(\@a,\@b); print "L と D\n"; for $i (0..N) { for $j (0..N) { if ($j <= $i) { printf("%14.10f\t", $a[$i][$j]); } else { printf("%14.10f\t", $a[$j][$i]); } } print "\n"; } print "\n"; # Ly=b から y を求める (前進代入) my @y = (0,0,0,0); forward_substitution(\@a,\@b,\@y); # y の 値 を確認 print "Y\n"; for $i (0..N) { printf("%14.10f\t", $y[$i]); } print "\n"; # DL^Tx=y から x を求める (後退代入) backward_substitution(\@a,\@y,\@x); } # 前進消去 sub forward_elimination { my ($a, $b) = @_; for $pivot (0..N) { # pivot < k の場合 my $s = 0; for $col (0..($pivot-1)) { $s = $$a[$pivot][$col]; for $k (0..($col-1)) { $s -= $$a[$pivot][$k] * $$a[$col][$k] * $$a[$k][$k]; } $$a[$pivot][$col] = $s / $$a[$col][$col]; } # pivot == k の場合 $s = $$a[$pivot][$pivot]; for $k (0..($pivot-1)) { $s -= $$a[$pivot][$k] * $$a[$pivot][$k] * $$a[$k][$k]; } $$a[$pivot][$pivot] = $s; } } # Ly=b から y を求める (前進代入) sub forward_substitution { my ($a, $b, $y) = @_; for $row (0..N) { for $col (0..$row) { $b[$row] -= $a[$row][$col] * $$y[$col]; } $$y[$row] = $b[$row]; } } # Ux=y から x を求める (後退代入) sub backward_substitution { my ($a, $y, $x) = @_; for ($row = N; $row >= 0; $row--) { for ($col = N; $col > $row; $col--) { $$y[$row] -= $a[$col][$row] * $a[$row][$row] * $$x[$col]; } $$x[$row] = $$y[$row] / $a[$row][$row]; } } # 状態を確認 sub disp_progress { my ($a) = @_; for $i (0..N) { for $j (0..N) { printf("%14.10f\t", $a[$i][$j]); } print "\n"; } print "\n"; } |