書籍「アートで魅せる数学の世界」のp.160で解説されている多項式型の数列を用いたストリング・アートについて再現を試みています。
多項式型の数列
多項式型の数列は以下のようなものです。\[ s_4(i) = i^{\alpha} (i=0,1,2,\cdots,P) \]この数列によるストリング・アートを\(\alpha = 2\)の場合と\(\alpha = 3\)の場合とに分けて解説します。
\( \alpha = 2 \)の場合
まず、\( \alpha = 2 \)の場合の多項式型の数列によるストリング・アートを再現してみました。
ソースコード
多項式型の数列によるストリング・アートのプログラムのソースコードを示しておきます。
void setup(){
size(500,500);
translate(width/2.0, height/2.0);
noFill();
// 多項式型の数列によるストリング・アートを描画
background(255,255,255);
int P = 1000;
float[] s4 = makeSequence_s4(2.0, P);
stroke(220,220,0);
strokeWeight(0.1);
drawSequence(200.0, s4, 691.0, P);
}
// 多項式型の数列s4を生成する関数
float[] makeSequence_s4(
float alpha,
int P
){
float[] s = new float[P+1];
for(int i=0; i<=P; i++){
s[i] = pow((float)i, alpha);
}
return s;
}
// 数列によるストリング・アートを描く関数
void drawSequence(
float R, // 振幅
float[] s, // 数列
float M, // 周期
int P // データ数
){
float x, y, theta;
beginShape();
for(int i=0; i<=P; i++){
theta = 2.0 * PI * s[i] / M;
x = R * cos( theta );
y = R * sin( theta );
vertex(x,y);
}
endShape();
}
\( \alpha = 3 \)の場合
次に、\( \alpha = 3 \)の場合の多項式型の数列によるストリング・アートを再現してみました。上記に示したソースコードで\(\alpha=3\)として描きましたが、書籍「アートで魅せる数学の世界」のp.160の図3.76の下2つの図とは異なる結果となりました。
失敗の原因は丸め誤差
\( \alpha = 3 \)の場合の多項式型の数列によるストリング・アートの描画で失敗した理由は、どうも丸め誤差が原因のようです。例えば、\(999^3\)をProcessingで2通りの方法で計算してみます。
println(999*999*999); // int型の999を3回掛ける
println(pow(999.0,3.0)); // float型の999.0をpow関数で3乗する
結果は、
997002999
9.9700301E8
となります。つまり、float型では有効数字が7桁であるため丸め誤差が生じており、int型で計算した数「\(997002999\)」と異なる値になります。この丸め誤差の発生を抑える形でソースコードを修正した結果、以下のように書籍「アートで魅せる数学の世界」のp.160の図3.76の下2つの図と同じ結果を得ることができました。
ソースコード(修正版)
\(\alpha=3\)の場合にも対応できるように修正した、多項式型の数列によるストリング・アートのプログラムのソースコードを示しておきます。
void setup(){
size(500,500);
translate(width/2.0, height/2.0);
noFill();
// 多項式型の数列によるストリング・アートを描画
background(255,255,255);
int P = 1000;
float M = 330.0;
float[] s4 = makeSequence_s4_rev2(3, M, P);
stroke(0,0,255);
strokeWeight(0.5);
drawSequence(200.0, s4, M, P);
}
// 多項式型の数列s4を生成する関数(修正バージョン)
float[] makeSequence_s4_rev2(
int alpha,
float M,
int P
){
int m = (int)M;
int s_temp;
float[] s = new float[P+1];
for(int i=0; i<=P; i++){
s_temp = 1;
for(int j=0; j<alpha; j++){
s_temp *= i;
}
s[i] = (float)(s_temp % m);
}
return s;
}
// 数列によるストリング・アートを描く関数
void drawSequence(
float R, // 振幅
float[] s, // 数列
float M, // 周期
int P // データ数
){
float x, y, theta;
beginShape();
for(int i=0; i<=P; i++){
theta = 2.0 * PI * s[i] / M;
x = R * cos( theta );
y = R * sin( theta );
vertex(x,y);
}
endShape();
}