XSLT存档  

不及格的程序员-八神

 查看分类:  ASP.NET XML/XSLT JavaScripT   我的MSN空间Blog

 

算法级别的难,举个例子,Quake 3中求反*方根的算法,没人解释基本看不懂:

float InvSqrt (float x){
    float xhalf = 0.5f*x;
    int i = *(int*)&x;
    i = 0x5f3759df - (i>>1);
    x = *(float*)&i;
    x = x*(1.5f - xhalf*x*x);
    return x;
}

 


 

首先划分数字成组,不管是整数还是小数,均以小数点为分界线,向左和向右每两位数字划为一个单元(整数的话直接向左划分),直到不够两个数字为止。比如:

12345,可以看做1,23,45;

1234,可以看做12,34;

0.123看一看做0.12,3;

0.1234可以看做0.12,34。

手动开*方根/手工开根号
  1. 以7654.321为例,按照之前的划分可以看作76,54.32,1,首先计算76,9的*方是81,超过76了,不行;再看8的*方64,没有超76,差值等于12,参见下图。

    手动开*方根/手工开根号
  2. 关键的一步到了,和除法一样下移数字,只是这里下移两位,移下来组成1254;而根结果现在只有一个8,取8*20=160,但160中的个位数字0先空着,计算16X*X刚不超过1254,这里算出是7,168*8超了,169*9更不行;算出差值为85。

    手动开*方根/手工开根号
  3. 同理下移32,组成8532,这时的根结果为87,取87*20=1740,个位的0先空着,心算1745*5肯定会超,应该是1744*4=6976,计算出差值1556。

    手动开*方根/手工开根号
  4. 这时候只剩下1了,而下移两位是必须的,所以补0,即下移10组成155610;这时的根结果为874,取874*20=17480,个位先空着,计算出17488*8正合适,计算出差值15706。

    手动开*方根/手工开根号
 

如果还想计算下去,继续下移两个零,组成1570600,取8748*20=174960,这里估算还是8,即174968*8,以下具体步骤就省略了,这时的开方结果得到为87.488,或四舍五入为87.49。如果要求只保留一位小数,则结果就为87.5。当然若想求得更准确的位数,如法炮制计算下去就可以了。

手动开*方根/手工开根号
手动开*方根/手工开根号
 
 

计算5的开方,先bai上2,5-2*2=1,小数点右边du补两位zhi零,按100试dao商,试3,(2*20+3)zhuan*3>100,试2,(2*20+2)*2<100,上2,余100-(2*20+2)*2=16,接着shu右边补两位零,同理,按1600试商,上4,(22*20+4)*4>1600,上3,余1600-(22*20+3)*3=271,同理,按27100试商,上7,(223*20+7)*7=31296>27100,只能上6,(223*20+6)*6=26796,余27100-26796=304...
得2.236
基本就是试商,用20乘前一次得到的商加上将要试的数,用他们的和再与要试的数乘,再用得到的结果比较。就是比除法复杂点。


举个例子,1156是四位数,所以它的算术bai*方根的整数部分是两位数,且易观察出其中的十位数是3。于是问题的关键在于:如何求出它的个位数a?为此,我们从a所满足的关系式来入手。

根据两数和的*方公式,可以得到

1156=(30+a)^2=30^2+2×30a+a^2,

所以 1156-30^2=2×30a+a^2,

即 256=(30×2+a)a,

也就是说, a是这样一个正整数,它与30×2的和,再乘以它本身,等于256。

为便于求得a,可用下面的竖式来进行计算:

根号上面的数3是*方根的十位数。将 256试除以30×2,得4(如果未除尽则取整数位).由于4与30×2的和64,与4的积等于256,4就是所求的个位数a。竖式中的余数是0,表示开方正好开尽。于是得到 1156=34^2, 或√1156=34. 上述求*方根的方法,称为笔算开*方法,用这个方法可以求出任何正数的算术*方根,它的计算步骤如下:

开方的计算步骤

1.将被开方数的整数部分从个位起向左每隔两位划为一段,用“ ' ”这个符号分开(竖式中的11’56),分成几段,表示所求*方根是几位数;

2.根据左边第一段里的数,求得*方根的最高位上的数(竖式中的3);

3.从第一段的数减去最高位上数的*方,在它们的差的右边写上第二段数组成第一个余数(竖式中的256);

4.把求得的最高位数乘以20去试除第一个余数,所得的最大整数作为试商(20×3除256,所得的最大整数是 4,所以试商是4);

5.用商的最高位数的20倍加上这个试商再乘以试商,如果所得的积小于或等于余数,试商就是*方根的第二位数;如果所得的积大于余数,就把试商减小之后再试(竖式中(20×3+4)×4=256,说明试商4就是*方根的第二位数);

6.用相同的方法,继续求*方根的其余各位上的数。

如碰到开不尽的情况,可根据所要求的精确度求出它的*似值。例如求其*似值(精确到0.01),可列出上面右边的竖式,并根据这个竖式得到。

笔算开*方运算较复杂,在实际中直接应用较少,但用这个方法可求出一个数的*方根的具有任意精确度的*似值。

 

参考资料:百度百科-开*方运算


 

例如:65536的手算开*方

 

Step1:将被开方数(为了形象,表述成“被除bai数”,此例中即为65536)从个位往高位每两位一断写成6,55,35的形式,为了方便表述,以下每一个“,”称为一步。 

Step2:从高位开始计算开方。例如第一步为6,由于2^2=4<6<9=3^2,因此只能商2(这就是和除法不同的地方,“除数”和“商”的计算位必须相同)。于是将2写在根号上方,计算开方余项。即高位余项加一步低位,此例中,即为高位余项2和低位一步55,余项即为255。

Step3:将Step2得到的第一步开方得数2乘以20(原理在后面证明)作为第二步除数的高位。即本步除数是4x(四十几)。按照要求,本步的商必须是x。因为45×5=225<255<46×6=276,所以本步商5。 

Step4:按照类似方法,继续计算以后的各步。其中,每一步的除数高位都是20×已求出的部分商。例如第三步的除数高位就是25×20=500,所以第三步除数为50x。本例中,506×6=3036恰好能整除,所以256就是最终计算结果。

扩展资料:

整数开*方步骤:

(1)将被开方数从右向左每隔2位用撇号分开; 

(2)从左边第一段求得算数*方根的第一位数字; 

(3)从第一段减去这个第一位数字的*方,再把被开方数的第二段写下来,作为第一个余数; 

(4)把所得的第一位数字乘以20,去除第一个余数,所得的商的整数部分作为试商(如果这个整数部分大于或等于10,就改用9左试商,如果第一个余数小于第一位数字乘以20的积,则得试商0);

(5)把第一位数字的20倍加上试商的和,乘以这个试商,如果所得的积大于余数时,就要把试商减1再试,直到积小于或等于余数为止,这个试商就是算数*方根的第二位数字; 

(6)用同样方法继续求算数*方根的其他各位数字。 2、小数部分开*方法: 求小数*方根,也可以用整数开*方的一般方法来计算,但是在用撇号分段的时候有所不同,分段时要从小数点向右每隔2段用撇号分开。

如果小数点后的最后一段只有一位,就填上一个0补成2位,然后用整数部分开*方的步骤计算。

任意数开立方根笔算步骤如下:

1、把所求数从右往左每3位分一段分成若干段,从左往右开始计算;

2、先从最左边一段开始计算。用试算法得出这段的得数(该得数要取其立方不溢出所求数第一段上的数时的最大数)设该得数为A;

3、把第一段所求数与A^3的差,在其后面按位补上第二段的数,为第二段要算的数(所求数),取一个试算数B,在计算纸的其它地方第一行写上3A^2,第二行往右移一位写上3AB,第三行往右移一位写上B^2,用竖式加法算出这三行数的和(上面两行数,相应空位补上0).用这个和乘以试算数B所得的积与该段所求数进行比较.试算出最大的B(积不溢出所求数),该数B即为第二段上的得数.把该得数写在算式相应段的上方。

4、相同的方法进行下一段的计算,所不同的是A要取前面已算出的得数,(如前面两位得数分别是1,3,A就取13,如算到第四段,前面三位数分别是1,3,5,A就取135,)试算出相应的B写在该段上方。

5、算到最后一段,如最后试算出来的余数不为0,则说明所求数的立方根不是整数,此时,用与求开方相似的方法,在该数后面补一段000,再算出的得数就是小数点后的第一位数,还有余数,再补三位0,只到余数为0或者至算至足够的小数位即可。

 


 

开根号时为什么乘20

 

拍照搜题,秒出答案,一键查看所有搜题记录


牛顿法求解*方根(一种计算机实现开根的方式)

前言

最*看到一个非常有趣的方法,叫做牛顿法,可以用于求解一个数的*方根,当然可以扩展到求实数或复数域。

牛顿法

话不多说直接上图,一目了然。
牛顿法
我们先在一个点x n x_nxn处做切线,然后这条切线与x轴的交点x n + 1 x_{n+1}xn+1就是我们下一个做切线的位置。

如果是二次函数的话,是很简单的导数运算,切线方程:y = f ′ ( x n ) ( x − x n ) + f ( x n ) y = f&#x27;(x_n)(x - x_n) + f(x_n)y=f(xn)(xxn)+f(xn),求交点就是把y置为零就可以了。

推导出这个公式------->x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1}=x_n-\frac{f(x_n)}{f&#x27;(x_n)}xn+1=xnf(xn)f(xn)!!

看图就会发现离真实的解越来越*了,多次迭代就可以得出*似值,是不是很简单?

不过牛顿法还是有限制的:

  1. 需要区间内f ′ ( x ) f&#x27;(x)f(x)≠0,不然无法求交点
  2. 在x求解区间内,f ′ ′ ( x ) f&#x27;&#x27;(x)f(x)是连续的

Go代码

语言大同小异,其实还是比较容易看懂的,就是循环了十次,当然次数越多越逼*啊!

func Sqrt(x float64) float64 {
	z := 1.0
	for i := 1; i <= 10; i++ {
		z -= (z*z - x) / (2*z)
	}
	return z
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

x是目标值,z是目标值的*方根需要被求解。

所求函数是f ( z , x ) = z 2 − x f(z,x)=z^2-xf(z,x)=z2x,对z求偏导∂ f ( z , x ) ∂ z = 2 z \frac{\partial f(z,x)}{\partial z}=2zzf(z,x)=2z。

代入x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1}=x_n-\frac{f(x_n)}{f&#x27;(x_n)}xn+1=xnf(xn)f(xn)就是中间循环的内容z -= (z*z - x) / (2*z)


参考链接:

  1. https://zh.wikipedia.org/wiki/牛顿法

牛顿法开*方

需求

计算一个整数的*方根。

分析

牛顿迭代法

牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上*似求解方程的方法。多数方程不存在求根公式,因此求精确根非常困难,甚至不可能,从而寻找方程的*似根就显得特别重要。方法使用函数f(x)的泰勒级数的前面几项来寻找方程f(x) = 0的根。牛顿迭代法是求方程根的重要方法之一,其最大优点是在方程f(x) = 0的单根附*具有*方收敛,而且该法还可以用来求方程的重根、复根,此时线性收敛,但是可通过一些方法变成超线性收敛。另外该方法广泛用于计算机编程中。

代码

#include <cstdio>
#include <iostream>
using namespace std;
#define LIMIT 0.001
int main()
{
    int n;
    cin >> n;
    double x = n / 2, c = x + 1 + LIMIT;
    while(x - c > LIMIT || c - x > LIMIT) {
        c = x;
        x = (x + n / x) / 2;
    }
    cout << x << endl;
    return 0;
}

 

输出测试

这里写图片描述

 

手动开*方的几种方法

学习 2018-7-7 
2407阅读43点赞31评论

一、死算法

这种方法适合较小数的开*方,比如√5,首先整数部分肯定是2,之后小数部分一个一个试,比如2.1 x 2.1=4.41,2.2 x 2.2=4.84,2.3 x 2.3=5.29,很显然2.3超了,前两位就是2.2,如果还要继续算的话:

2.21 x 2.21=4.8841

2.22 x 2.22=4.9284

2.23 x 2.23=4.9729

2.24 x 2.24=5.0176

那么前三位就是2.23

事实也的确如此

【附加知识】√5-1再除以2的值就是黄金分割率,黄金分割率有十分特殊的性质,在斐波那契数列中也有运用。

二、竖式法

上面那种未免工作量太大了

网传一种列竖式的方法,这里摘抄给大家:

1.先将一组数,以小数点为起点,每隔两位画个记号,比如4856.341,记号为48丨56.34丨1

2.首先看48,7x7=49,大了,就取6 x 6=36,算出差为12,带到下一行,然后下移56,组成1256

3.这时,我们已经知道一位是6,就取6 x 20=120(这里20为常数),然后寻找12X x X≤1256(12X中的X指个位数字,不是12和X的乘积!)发现是129x9=1161,求出差值95,算出前两位为69

4.再将数字带下去得9534,取69 x 20=1380,寻找138X x X≤9534,发现为1386 x 6,得出前3位为69.6

如果你想算可以继续算下去

三、渐进分数

德国数学家克莱因给渐进分数了一个很有趣的几何解释,在*面直角坐标系的原点出发,射出一条射线,这条射线不经过坐标系中任何整数坐标点,此时y=ax,其中a一定是无理数,将这条射线左右摆动,会碰到一些点,这些点对应的就是这个无理数的渐进分数。

回归正题,加入我们要求√11的值,可以这样变换

图源《数学的源与流》张顺燕 编著

继续变换下去,就可以得到封面上的写的式子

当然,这里的+号并不是单纯的+,而是降层符号

那么√11的第一个渐进分数为3,第二个渐进分数为3+1/3,约等于3.33

第三个渐进分数为3+1/(3+1/6)=63/19,约等于3.3158

第四个渐进分数为3+1/[3+1/(6+1/3)]=199/60,约等于3.3167

越来越接*
程序我们可以看到a,b是迭代变量,迭代关系是temp = a % b;根据迭代关系我们可以由旧值推出新值,然后循环执a = b; b = temp;直到迭代过程结束(余数为0)。在这里a好比那个胆小鬼,总是从b手中接过位置,而b则是那个努力向前冲的先锋。

斐波那契数列

还有一个很典型的例子是斐波那契(Fibonacci)数列。斐波那契数列为:0、1、1、2、3、5、8、13、21、…,即 fib⑴=0; fib⑵=1;fib(n)=fib(n-1)+fib(n-2) (当n>2时)。
在n>2时,fib(n)总可以由fib(n-1)和fib(n-2)得到,由旧值递推出新值,这是一个典型的迭代关系,所以我们可以考虑迭代算法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int Fib(int n) //斐波那契(Fibonacci)数列
{
if (n < 1)/*预防错误*/
return 0;
if (n == 1 || n == 2)/*特殊值,无需迭代*/
return 1;
int f1 = 1,f2 = 1,fn;/*迭代变量*/
int i;
for(i=3; i<=n; ++i)/*用i的值来限制迭代的次数*/
{
fn = f1 + f2; /*迭代关系式*/
f1 = f2;//f1和f2迭代前进,其中f2在f1的前面
f2 = fn;
}
return fn;
}
 
 

 

 
 
posted on 2021-06-25 11:18  不及格的程序员-八神  阅读(181)  评论(0编辑  收藏  举报