牛顿迭代法 #
可用来收敛到一个点,通过不停的迭代,求方程的近似根。
这是一个简单的曲线,如果我们要用牛顿法求f(x) = 0,第一步:那么首先需要先随便在横坐标上确认一个点。
然后第二步:做垂直,与曲线有一个交点,然后第三步:做这个交点的切线,这个切线再与x轴有一个交点,重复第一步,这样就能无限趋近于f(x) = 0
于是我们可以得到这样一个公式,$x0$是第一步随便确认的点,$x1$是新的于x轴的交点
牛顿迭代公式: $x1 = x0 - \frac{f(x0)}{f’(x0)}$
Shader部分 #
const int iter = 100;//迭代次数
//复数乘法运算
vec2 cmul(vec2 c1, vec2 c2) {
return vec2(c1.x*c2.x - c1.y*c2.y, c1.y*c2.x + c1.x*c2.y);
}
//复数除法运算
vec2 cdiv(vec2 c1, vec2 c2) {
float d = dot(c2, c2);
//考虑到分母为0的情况
if(d == 0.) return c1;
else return vec2((c1.x*c2.x + c1.y*c2.y)/d, (c1.y*c2.x - c1.x*c2.y)/d);
}
//迭代
int itt(vec2 x0) {
for(int i = 0; i <= iter; i++) {
//x1 = x0 - (x0^3 - 1)/3*x0, 也就是x1 = x0 - f(x)/f'(x)
vec2 x1 = x0 - cdiv(cmul(cmul(x0, x0), x0) - 1., 3.*x0);
//当x1与x0无限接近的时候,返回当前的迭代次数
if(distance(x1, x0) < .0000001) {
return i;
}
x0 = x1;
}
//不满足的话,返回最大的迭代次数
return iter;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
//让uv坐标中心设置在中心
vec2 uv = fragCoord/iResolution.xy - .5;
//根据不同迭代次数显示灰度
vec3 col = vec3(float(itt(uv))/float(iter));
// Output to screen
fragColor = vec4(col,1.0);
}
注:我第一次写的时候在main里面写for,然后如果无限接近就break,但是这种方法貌似有一些问题,我最后得到的图像是二值化的。