Perlで書き直した

3次スプライン曲線の描き方について調べていたんだけど、
アルゴリズムと入力と出力の例みたいのを見つけたので書き直してみた。

参考にしたサイトはこちら。

3次スプライン補間法
http://next1.msi.sk.shibaura-it.ac.jp/MULTIMEDIA/numeanal/node16.html

use v5.14;
use strict;
use warnings;

my @points = (
    [ 0.9, 1.3  ],
    [ 1.3, 1.5  ],
    [ 1.9, 1.85 ],
    [ 2.1, 2.1  ],
    [ 2.6, 2.6  ],
    [ 3.0, 2.7  ],
    [ 3.9, 2.4  ],
    [ 4.4, 2.15 ],
    [ 4.7, 2.05 ],
    [ 5.0, 2.10 ],
    [ 6.0, 2.25 ],
    [ 7.0, 2.3  ],
    [ 8.0, 2.25 ],
    [ 9.2, 1.95 ]
);

my $n = scalar( @points ) - 1;
my @a_j = map { $_->[1]; } @points;

my @h_j = ();
for (my $i=0; $i<$n; $i++) {
    push @h_j, $points[$i+1]->[0] - $points[$i]->[0];
}

my @alpha_j = ( 0 );
for (my $i=1; $i<$n; $i++) {
    my $tmp  = ((3 / $h_j[$i]  ) * ($a_j[$i+1] - $a_j[$i  ]));
       $tmp -= ((3 / $h_j[$i-1]) * ($a_j[$i  ] - $a_j[$i-1]));
    push @alpha_j, $tmp;
}

my @l_j = ( 1 );
my @u_j = ( 0 );
my @z_j = ( 0 );

for (my $i=1; $i<$n; $i++) {
    push @l_j, ( (2 * ($points[$i+1]->[0] - $points[$i-1]->[0])) - ($h_j[$i-1] * $u_j[$i-1]) );
    push @u_j, $h_j[$i] / $l_j[$i];
    push @z_j, ($alpha_j[$i] - ($h_j[$i-1] * $z_j[$i-1])) / $l_j[$i];
}

push @l_j, ( 1 );
push @z_j, ( 0 );

my @b_j = map { 0; } 0..$n;
my @c_j = map { 0; } 0..$n;
my @d_j = map { 0; } 0..$n;
for (my $i=($n - 1); 0<=$i; $i--) {
    $c_j[$i] = $z_j[$i] - ($u_j[$i] * $c_j[$i+1]);
    $b_j[$i] = (($a_j[$i+1] - $a_j[$i]) / $h_j[$i]) - (($h_j[$i] / 3) * ($c_j[$i+1] + (2 * $c_j[$i])));
    $d_j[$i] = ($c_j[$i+1] - $c_j[$i]) / (3 * $h_j[$i]);
}

printf( "%2s, %6s, %6s, %6s, %6s, %6s\n",
    'i', 'x(i)', 'a(i)', 'b(i)', 'c(i)', 'd(i)' );
for (my $i=0; $i<=$n; $i++) {
    if ( $i == $n ) {
        printf( "%2d, %6.3f\n", $i, $points[$i]->[0] );
        next;
    }

    printf( "%2d, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f\n",
        $i, $points[$i]->[0], $a_j[$i], $b_j[$i], $c_j[$i], $d_j[$i] );
}
$ perl aaa.pl 
 i,   x(i),   a(i),   b(i),   c(i),   d(i)
 0,  0.900,  1.300,  0.540,  0.000, -0.248
 1,  1.300,  1.500,  0.421, -0.297,  0.947
 2,  1.900,  1.850,  1.087,  1.407, -2.956
 3,  2.100,  2.100,  1.295, -0.367, -0.447
 4,  2.600,  2.600,  0.593, -1.037,  0.445
 5,  3.000,  2.700, -0.022, -0.502,  0.174
 6,  3.900,  2.400, -0.503, -0.032,  0.078
 7,  4.400,  2.150, -0.477,  0.085,  1.314
 8,  4.700,  2.050, -0.071,  1.268, -1.581
 9,  5.000,  2.100,  0.262, -0.155,  0.043
10,  6.000,  2.250,  0.080, -0.027, -0.003
11,  7.000,  2.300,  0.017, -0.036, -0.031
12,  8.000,  2.250, -0.147, -0.128,  0.036
13,  9.200

スプライン曲線のコードを読む時は、
データの数がN個なのか、それとも補間区間の数がN個なのか把握する必要があって、
検索して見つけたものの多くは、
補間区間をN個とし、データの数はN+1個だった。

今回、苦戦したのは、
変数名にa(A)α(Alpha)が使われてて見分け付かなかった点で、
あと、後ろから係数を求めているのは「トーマス法」がキーワードっぽい。

とりあえず、おしまい。

Leave a Comment