我得到的是圆而不是曼德尔布罗
I get circle instead of mandelbrot
我试着严格遵循公式,但不知何故我得到的只是一个圆圈。 mandelbrot set coordinates,我明白了。
for(x=-50;x<50;x++){
for(y=-50;y<50;y++){
// Canvas pixel coordinates to -2,2
var x2 = x * 0.04;
var y2 = y * 0.04;
var i = 0;
var z = 0;
var c = Math.sqrt( x2*x2 + y2*y2 );
while(true) {
if( i > 20 || z > 4.0 ) {
break;
}
z = z*z + c;
i = i + 1;
}
}
}
jsFiddle:
https://jsfiddle.net/d4fj1n63/
您需要执行复杂的算术运算。
var x3 = 0, y3 = 0, k = 0;
while (x3*x3 + y3*y3 < 16 && k++ < 20) {
var tmp = x3*x3 - y3*y3 + x2;
y3 = 2*x3*y3 + y2;
x3 = tmp;
}
公式为zk+1 = zk2 + c, 与z0 = 0 或等效地 z1 = c
其中 c 是当前位置,即 c = x2
+ i⋅y2
.
我有 z = x3
+ i⋅y3
所以 z2 = (x3
+ i⋅y3
)2 = x3
2 + 2⋅i⋅x3
⋅y3
+ i2⋅y3
2.
i2 = −1 这简化为 z2 = (x3
2 − y3
2) + i⋅ (2⋅x3
⋅y3
) 并在其中添加 c
即 x2
和 y2
.
请参阅 https://jsfiddle.net/d5avqq5w/ 进行现场演示。
您的原始代码在 z = Math.sqrt( x2*x2 + y2*y2 )
步骤中丢弃了角度信息,因为在那之后未使用 x2
和 y2
。因此生成的颜色必须与角度无关,即由同心圆组成。
The page you gave as a reference处理复数的绝对值。但是 Mandelbrot 公式的迭代步骤应该按原样对复数进行运算,而不是对复数的任何绝对值进行运算,因此这里使用该公式是不合适的。
绝对值有一个有效的应用,那就是决定是否终止循环(即检测发散)。 The other page you referenced 只是写了关于
The modulus (length) of zn exceeds a given value.
实际上没有明确给出阈值。我使用了 4 的阈值,但是我通过测试 z 的长度平方是否超过 16 来避免平方根。这就是我代码中 x3*x3 + y3*y3 < 16
的来源从。使用 2 作为阈值更常见(即 4 用于平方测试),但我觉得使用 4 会更接近您的代码,即更适合突出比较绝对值和比较其平方之间的区别.使用 4 而不是 2 可能会导致我们稍后检测到分歧,从而导致循环退出时计数器变量的值略高。
请注意,Wikipedia 也有一些伪代码,您可能已将其用作起点,并解释了代码中的实数值算法如何与其余部分的复数值算法相关联文章。
你犯了一个数学错误。C,Z 是复数,但你把它们当作实数。
我对您的代码进行了最小的修正,因此它按预期工作。
var canvas = $('canvas');
var ctx = canvas[0].getContext('2d');
for(x=-50;x<50;x++){
for(y=-50;y<50;y++){
var x2 = x * 0.04;
var y2 = y * 0.04;
var i = 0;
var z = 0;
//c - complex number. so c = x2+i*y2, where i^2 =-1
//var c = Math.sqrt( x2*x2 + y2*y2 );
var xi= x2;
var yi=y2;
while(true) {
if( i > 50 || xi*xi+yi*yi > 4.0 ) {
break;
}
// z - complex number, so on every step we should calculate real and imaginary parts
//z^2 = (x^2-y^2)+i*(2*x*y), i^2 =-1
var tmp = xi*xi - yi*yi+x2;
yi = 2*xi*yi+y2;
xi = tmp;
i = i + 1;
}
var color = parseInt(15/21*i).toString(16);
ctx.fillStyle = '#'+color+color+color;
ctx.fillRect((x+50)*2,(y+50)*2,2,2);
}
}
我试着严格遵循公式,但不知何故我得到的只是一个圆圈。 mandelbrot set coordinates,我明白了。
for(x=-50;x<50;x++){
for(y=-50;y<50;y++){
// Canvas pixel coordinates to -2,2
var x2 = x * 0.04;
var y2 = y * 0.04;
var i = 0;
var z = 0;
var c = Math.sqrt( x2*x2 + y2*y2 );
while(true) {
if( i > 20 || z > 4.0 ) {
break;
}
z = z*z + c;
i = i + 1;
}
}
}
jsFiddle: https://jsfiddle.net/d4fj1n63/
您需要执行复杂的算术运算。
var x3 = 0, y3 = 0, k = 0;
while (x3*x3 + y3*y3 < 16 && k++ < 20) {
var tmp = x3*x3 - y3*y3 + x2;
y3 = 2*x3*y3 + y2;
x3 = tmp;
}
公式为zk+1 = zk2 + c, 与z0 = 0 或等效地 z1 = c
其中 c 是当前位置,即 c = x2
+ i⋅y2
.
我有 z = x3
+ i⋅y3
所以 z2 = (x3
+ i⋅y3
)2 = x3
2 + 2⋅i⋅x3
⋅y3
+ i2⋅y3
2.
i2 = −1 这简化为 z2 = (x3
2 − y3
2) + i⋅ (2⋅x3
⋅y3
) 并在其中添加 c
即 x2
和 y2
.
请参阅 https://jsfiddle.net/d5avqq5w/ 进行现场演示。
您的原始代码在 z = Math.sqrt( x2*x2 + y2*y2 )
步骤中丢弃了角度信息,因为在那之后未使用 x2
和 y2
。因此生成的颜色必须与角度无关,即由同心圆组成。
The page you gave as a reference处理复数的绝对值。但是 Mandelbrot 公式的迭代步骤应该按原样对复数进行运算,而不是对复数的任何绝对值进行运算,因此这里使用该公式是不合适的。
绝对值有一个有效的应用,那就是决定是否终止循环(即检测发散)。 The other page you referenced 只是写了关于
The modulus (length) of zn exceeds a given value.
实际上没有明确给出阈值。我使用了 4 的阈值,但是我通过测试 z 的长度平方是否超过 16 来避免平方根。这就是我代码中 x3*x3 + y3*y3 < 16
的来源从。使用 2 作为阈值更常见(即 4 用于平方测试),但我觉得使用 4 会更接近您的代码,即更适合突出比较绝对值和比较其平方之间的区别.使用 4 而不是 2 可能会导致我们稍后检测到分歧,从而导致循环退出时计数器变量的值略高。
请注意,Wikipedia 也有一些伪代码,您可能已将其用作起点,并解释了代码中的实数值算法如何与其余部分的复数值算法相关联文章。
你犯了一个数学错误。C,Z 是复数,但你把它们当作实数。
我对您的代码进行了最小的修正,因此它按预期工作。
var canvas = $('canvas');
var ctx = canvas[0].getContext('2d');
for(x=-50;x<50;x++){
for(y=-50;y<50;y++){
var x2 = x * 0.04;
var y2 = y * 0.04;
var i = 0;
var z = 0;
//c - complex number. so c = x2+i*y2, where i^2 =-1
//var c = Math.sqrt( x2*x2 + y2*y2 );
var xi= x2;
var yi=y2;
while(true) {
if( i > 50 || xi*xi+yi*yi > 4.0 ) {
break;
}
// z - complex number, so on every step we should calculate real and imaginary parts
//z^2 = (x^2-y^2)+i*(2*x*y), i^2 =-1
var tmp = xi*xi - yi*yi+x2;
yi = 2*xi*yi+y2;
xi = tmp;
i = i + 1;
}
var color = parseInt(15/21*i).toString(16);
ctx.fillStyle = '#'+color+color+color;
ctx.fillRect((x+50)*2,(y+50)*2,2,2);
}
}