算法级别的难,举个例子,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。
-
以7654.321为例,按照之前的划分可以看作76,54.32,1,首先计算76,9的*方是81,超过76了,不行;再看8的*方64,没有超76,差值等于12,参见下图。
-
关键的一步到了,和除法一样下移数字,只是这里下移两位,移下来组成1254;而根结果现在只有一个8,取8*20=160,但160中的个位数字0先空着,计算16X*X刚不超过1254,这里算出是7,168*8超了,169*9更不行;算出差值为85。
-
同理下移32,组成8532,这时的根结果为87,取87*20=1740,个位的0先空着,心算1745*5肯定会超,应该是1744*4=6976,计算出差值1556。
-
这时候只剩下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'(x_n)(x - x_n) + f(x_n)y=f′(xn)(x−xn)+f(xn),求交点就是把y置为零就可以了。
推导出这个公式------->x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1}=x_n-\frac{f(x_n)}{f'(x_n)}xn+1=xn−f′(xn)f(xn)!!
看图就会发现离真实的解越来越*了,多次迭代就可以得出*似值,是不是很简单?
不过牛顿法还是有限制的:
- 需要区间内f ′ ( x ) f'(x)f′(x)≠0,不然无法求交点
- 在x求解区间内,f ′ ′ ( x ) f''(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)=z2−x,对z求偏导∂ f ( z , x ) ∂ z = 2 z \frac{\partial f(z,x)}{\partial z}=2z∂z∂f(z,x)=2z。
代入x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1}=x_n-\frac{f(x_n)}{f'(x_n)}xn+1=xn−f′(xn)f(xn)就是中间循环的内容z -= (z*z - x) / (2*z)
。
参考链接:
牛顿法开*方
需求
计算一个整数的*方根。
分析
牛顿迭代法(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;
}
输出测试
手动开*方的几种方法
一、死算法
这种方法适合较小数的开*方,比如√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
越来越接*斐波那契数列
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; } |
南来地,北往的,上班的,下岗的,走过路过不要错过!
======================个性签名=====================
之前认为Apple 的iOS 设计的要比 Android 稳定,我错了吗?
下载的许多客户端程序/游戏程序,经常会Crash,是程序写的不好(内存泄漏?刚启动也会吗?)还是iOS本身的不稳定!!!
如果在Android手机中可以简单联接到ddms,就可以查看系统log,很容易看到程序为什么出错,在iPhone中如何得知呢?试试Organizer吧,分析一下Device logs,也许有用.