有买王者荣耀体验服免费号号的吗?

你正在使用的浏览器版本过低,将不能正常浏览和使用知乎。单片机C语言求平方根函数
> 单片机C语言求平方根函数
单片机C语言求平方根函数
在单片机中要开平方.可以用到下面算法: 算法1: 本算法只采用移位、加减法、判断和循环实现,因为它不需要浮点运算,也不需要乘除运算,因此可以很方便地运用到各种芯片上去。我们先来看看10进制下是如何手工计算开方的。先看下面两个算式,x = 10*p + q (1)公式(1)左右平方之后得:x^2 = 100*p^2 + 20pq + q^2 (2)现在假设我们知道x^2和p,希望求出q来,求出了q也就求出了x^2的开方x了。我们把公式(2)改写为如下格式:q = (x^2 - 100*p^2)/(20*p+q) (3)这个算式左右都有q,因此无法直接计算出q来,因此手工的开方算法和手工除法算法一样有一步需要猜值。我们来一个手工计算的例子:计算的开方首先我们把这个数两位两位一组分开,计算出最高位为3。也就是(3)中的p,最下面一行的334为余数,也就是公式(3)中的(x^2 - 100*p^2)近似值 3 --------------- | 12 34 56 78 90 9 --------------- | 3 34下面我们要找到一个0-9的数q使它最接近满足公式(3)。我们先把p乘以20写在334左边: 3 q --------------- | 12 34 56 78 90 9 --------------- 6q| 3 34我们看到q为5时(60+q*q)的值最接近334,而且不超过334。于是我们得到: 3 5 --------------- | 12 34 56 78 90 9 --------------- 65| 3 34 | 3 25 --------------- 9 56接下来就是重复上面的步骤了,这里就不再啰嗦了。这个手工算法其实和10进制关系不大,因此我们可以很容易的把它改为二进制,改为二进制之后,公式(3)就变成了:q = (x^2 - 4*p^2)/(4*p+q) (4)我们来看一个例子,计算100(二进制1100100)的开方: 1 0 1 0 --------------- | 1 10 01 00 1 --------------- 100| 0 10 | 0 00 --------------- | 10 011001| 10 01 --------------- 0 00这里每一步不再是把p乘以20了,而是把p乘以4,也就是把p右移两位,而由于q的值只能为0或者1,所以我们只需要判断余数(x^2 - 4*p^2)和(4*p+1)的大小关系,如果余数大于等于(4*p+q)那么该上一个1,否则该上一个0。下面给出完成的C语言程序,其中root表示p,rem表示每步计算之后的余数,divisor表示(4*p+1),通过a>>30取a的最高 2位,通过a<<=2将计算后的最高2位剔除。其中root的两次<<1相当于4*p。程序完全是按照手工计算改写的,应该不难理解。unsigned short sqrt(unsigned long a){ unsigned long rem = 0; unsigned long root = 0; unsigned long divisor = 0; for(int i=0; i<16; i++){ root <<= 1; rem = ((rem <> 30)); a <<= 2; divisor = (root<<1) + 1; if(divisor <= rem){ rem -= root++; } } return (unsigned short)(root);}算法2 :单片机开平方的快速算法因为工作的需要,要在单片机上实现开根号的操作。目前开平方的方法大部分是用牛顿迭代法。我在查了一些资料以后找到了一个比牛顿迭代法更加快速的方法。不敢独享,介绍给大家,希望会有些帮助。1.原理因为排版的原因,用pow(X,Y)表示X的Y次幂,用B[0],B[1],...,B[m-1]表示一个序列,其中[x]为下标。假设: B[x],b[x]都是二进制序列,取值0或1。 M = B[m-1]*pow(2,m-1) + B[m-2]*pow(2,m-2) + ... + B[1]*pow(2,1) + B[0]*pow(2,0) N = b[n-1]*pow(2,n-1) + b[n-2]*pow(2,n-2) + ... + b[1]*pow(2,1) + n[0]*pow(2,0) pow(N,2) = M (1) N的最高位b[n-1]可以根据M的最高位B[m-1]直接求得。 设 m 已知,因为 pow(2, m-1) <= M <= pow(2, m),所以 pow(2, (m-1)/2) <= N <=pow(2, m/2) 如果 m 是奇数,设m=2*k+1, 那么 pow(2,k) <= N < pow(2, 1/2+k) < pow(2, k+1), n-1=k, n=k+1=(m+1)/2 如果 m 是偶数,设m=2k, 那么 pow(2,k) > N >= pow(2, k-1/2) > pow(2, k-1), n-1=k-1,n=k=m/2 所以b[n-1]完全由B[m-1]决定。 余数 M[1] = M - b[n-1]*pow(2, 2*n-2) (2) N的次高位b[n-2]可以采用试探法来确定。 因为b[n-1]=1,假设b[n-2]=1,则 pow(b[n-1]*pow(2,n-1) + b[n-1]*pow(2,n-2),2) = b[n-1]*pow(2,2*n-2) + (b[n-1]*pow(2,2*n-2) + b[n-2]*pow(2,2*n-4)), 然后比较余数M[1]是否大于等于 (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4)。这种比较只须根据B[m-1]、B[m-2]、...、B[2*n-4]便可做出判断,其余低位不做比较。 若 M[1] >= (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4), 则假设有效,b[n-2] =1; 余数 M[2] = M[1] - pow(pow(2,n-1)*b[n-1] + pow(2,n-2)*b[n-2], 2) = M[1] -(pow(2,2)+1)*pow(2,2*n-4); 若 M[1] < (pow(2,2)*b[n-1] + b[n-2]) * pow(2,2*n-4), 则假设无效,b[n-2] =0;余数 M[2] = M[1]。 (3) 同理,可以从高位到低位逐位求出M的平方根N的各位。使用这种算法计算32位数的平方根时最多只须比较16次,而且每次比较时不必把M的各位逐一比较,尤其是开始时比较的位数很少,所以消耗的时间远低于牛顿迭代法。2. 实现代码这里给出实现32位无符号整数开方得到16位无符号整数的C语言代码。--------------------------------------------------------------------------------unsigned int sqrt_16(unsigned long M){ unsigned int N, unsigned long tmp, // 结果、循环计数 if (M == 0) // 被开方数,开方结果也为0 return 0; N = 0; tmp = (M >> 30); // 获取最高位:B[m-1] M <<= 2; if (tmp > 1) // 最高位为1 { N ++; // 结果当前位为1,否则为默认的0 tmp -= N; } for (i=15; i>0; i--) // 求剩余的15位 { N <<= 1; // 左移一位 tmp <<= 2; tmp += (M >> 30); // 假设 ttp = N; ttp = (ttp<<1)+1; M <<= 2; if (tmp >= ttp) // 假设成立 { tmp -= N ++; } } return N;}本文引用地址:
分享给小伙伴们:
我来说两句……
最新技术贴
微信公众号二
微信公众号一单片机c语言求解解决方案 - C语言当前位置:& &&&单片机c语言求解解决方案单片机c语言求解解决方案&&网友分享于:&&浏览:1次单片机c语言求解下面这个程序是一个不完整的程序,我是想知道问什么我触发了swith里面的b,结果我12864上显示的不是二进制而是一个0这是怎么回事?sumsz是一个uchar型的全局变量char *itoa(int num,char *str,int radix){ /* 索引表 */ char index[]=&ABCDEFGHIJKLMNOPQRSTUVWXYZ&;
/* 中间变量 */// unum=(unsigned) int i=0,j,k=0; do {
str[i++]=index[unum%(unsigned)radix];
unum/= } while(unum); str[i]='\0'; /* 将原来的“/2”改为“/2.0”,保证当num在16~255之间,radix等于16时,也能得到正确结果 */ for(j=k;j&=(i-1)/2+k;j++) {
num=str[j];
str[j]=str[i-j-1+k];
str[i-j-1+k]= }
strcpy(sumsz,str);
& }/**********************运算程序******************************/void yuans()
//运算函数{ &
uchar i,j,temp1; uchar xdata ch[30];//
switch(sym)
case 'h':sprintf(sumsz,&%x&,(int)number1); //两数相加 &
case 'o':sprintf(sumsz,&%o&,(int)number1); //两数相减 &
case 'b':itoa((int)number1,ch,2); //两数相乘 &
case '/':number1/=number2;
//两数相除 &
j=strlen(sumsz);
write_com(0x88);
for(i=0;i&j;i++)
//显示结果 &
/* if(sumsz[i]=='.')
if(flag==1)
//temp1=sumsz[i]; &
//write_data(temp1); &
//delay(10);&
temp1=sumsz[i]; &
write_data(temp1); &
delay(10); &
//number2=0;}------解决方案--------------------
这种问题可以单步找的,不知道你用的下载器支不支持单步调试的。不行的话,用串口调试,把变量的值,发到串口助手上看。
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有单片机C语言的一些误用和知识
在学习的时候才真正知道是什么它是来干什么的~但是C语言用到嵌入式只是它小小的一部分他的应用还有很多地方呢,呵呵我们这里就不讨论这个了。我们是不是在写程序的时候错误很多就算编译通过了也达不到我们预期的结果,完了自己是不是也很难找到错在哪儿吧?我绝得语言之所以能称之为语言,它肯定是一种工具一种相互交流相互通信相互传达之间的意图的工具,作为语言那肯定得有自己的语法,要想相互交流肯定得先学好它的语法吧(比如像表达式,函数,循环,指针)我称之为C语言的语法。C语言虽然很强大但是他也有不少陷阱,所以我发这篇帖子有两个目的:一是把C语言一些误用易错的地方总结一下,二是把C语言一些基本语法总结一下。  第一次:  1.关于自增自减(即++i,i++)  要想给一个数加一或减一我们可以:  i&+=&1;  j&-=&1;  而C语言还允许用++和--运算符,其实这里有误导,因为++和--可以作为前缀和后缀,这样的话他们就有可能改变操作数的值,下面让我们来看看:  i&=&1;  printf(&i&is&%d\n&,++i);&/*&prints&i&is&2&*/  printf(&i&is&%d\n&,i);&/*&prints&i&is&2&*/  计算表达式i++的结果是i,但是会引发i随后进行自增:  i&=&1;  printf(&i&is&%d\n&,i++);&/*&prints&i&is&1/&*/  printf(&i&is&%d\n&,i);&/*&prints&i&is&2&*/  第一个printf&显示了i自增前的原始值,第二个printf显示了i变化后的新值;当然&--&类似我就不举例了~  但在同一个表达式中多次使用++和--往往很难理解我们看看下面的例子:  i&=&1;  j&=&2;  k&=&++i&+&j++;  i,j,k最终值分别是2,3,4而++i是2&j++是2;  总结:不管是++i还是i++执行这条语句后i的值都加一了只是(++i)的值加一了而(i++)没变,  2.typedef与#define  2.1.typedef  C语言除了直接使用标准的类型名(如&int&char&float&double)和自己声明的结构体、共用体、指针、枚举类型外,还可以用typedef声明新的类型名来代替现有的类型名。  typedef&unsigned&char&u8;  typedef&unsigned&int&u16;  u8&  u16&  typedef&struct  {  u8&  u8&  u16&  }DATE;  DATE&  总结一下,声明新的类型名的方法:  1.先按定义变量的方法写出定义体(如&unsigned&int&i)  2.在变量名换成新的变量名(如将&i换成u16)  3.在最前面加上typedef&(typedef&unsigned&int&u16)  4.然后用新类型名去定义变量  2.2&#define  2.1.1不带参数的宏定义  define&标识符&字符串  define&PI&3.1415926  注意:  1.它的作用是在本程序中用指定的标识符PI来代替3.1415926  2.宏定义是用宏来代替字符串也就是做简单的置换,不做正确性检查如果写成  define&PI&3.l4l6926  即把1写成了字母l但是预处理照常代入不做任何语法检查!!  2.1.2带参数的宏定义  define&宏名(参数)&字符串  define&S(a,b)&a*b  area&=&S(a,b);  define&MAX(x,y)&(x)&(y)&?&(x):(y)  3.typedef和#define的区别  一般来说typedef&因为它能正确处理指针类型  typedef&char&*String1;  define&String2&char&*  String1&s1,s2;  String2&s3,s4;  s1,s2,s3&被定义为了char*&但s4却被定义为了char型  3.&static&变量  static变量大致分为三种用法  1.&用于局部变量中,成为静态局部变量.&静态局部变量有两个用法,记忆功能和全局生存期.  2.&用于全局变量,主要作用是限制此全局变量被其他的文件调用.  3.&用于类中的成员.表示这个成员是属于这个类但是不属于类中任意特定对象  1.&静态局部变量  静态局部变量属于静态存储方式,它具有以下特点:  (1)静态局部变量在函数内定义&它的生存期为整个源程序,但是其作用域仍与自动变量相同,只能在定义该变量的函数内使用该变量。退出该函数后,&尽管该变量还继续存在,但不能使用它。  (2)允许对构造类静态局部量赋初值&例如数组,若未赋以初值,则由系统自动赋以0值。  (3)&对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。&根据静态局部变量的特点,&可以看出它是一种生存期为整个源程序的量。虽然离开定义它的函数后不能使用,但如再次调用定义它的函数时,它又可继续使用,&而且保存了前次被调用后留下的值。&因此,当多次调用一个函数且要求在调用之间保留某些变量的值时,可考虑采用静态局部变量。虽然用全局变量也可以达到上述目的,但全局变量有时会造成意外的副作用,因此仍以采用局部静态变量为宜。  举例如下:  void&fun()  {  static&int&a&=&1;  a++;  }  在第一次进入这个函数的时候,变量a被初始化为1!并接着自增1,以后每次进入该函数,a就不会被再次初始化了,仅进行自增1的操作;在static发明前,要达到同样的功能,则只能使用全局变量:  int&a&=&1;  void&fun()  {  a++;  }  2.静态全局变量  全局变量(外部变量)的之前再加上static&就构成了静态的全局变量。全局变量本身就是静态存储方式,&静态全局变量当然也是静态存储方式。&这两者在存储方式上并无不同。这两者的区别虽在于,非静态全局变量的作用域是整个源程序,&当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。&而静态全局变量则限制了其作用域,&即只在定义该变量的源文件内有效,&在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,&因此可以避免在其它源文件中引起错误。从以上分析可以看出,&把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,&限制了它的使用范围。因此static&这个说明符在不同的地方所起的作用是不同的。  3.static的类成员变量  static关键字有两种意思,你看上下文来判断  1.表示变量是静态存储变量,表示变量存放在静态存储区.  2.表示该变量是内部连接(这种情况是指该变量不在任何{}之内,就象全局变量那样,这时候加上static),也就是说在其它的.cpp文件中,该变量是不可见的(你不能用).  二、static&函数&——&内部函数和外部函数  当一个源程序由多个源文件组成时,C语言根据函数能否被其它源文件中的函数调用,将函数分为内部函数和外部函数。  1&内部函数(又称静态函数)  如果在一个源文件中定义的函数,只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用,这种函数称为内部函数。  定义一个内部函数,只需在函数类型前再加一个“static”关键字即可,如下所示:  static&函数类型&函数名(函数参数表)  {……}  关键字“static”,译成中文就是“静态的”,所以内部函数又称静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件。  使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名,因为同名也没有关系。  2&外部函数  外部函数的定义:在定义函数时,如果没有加关键字“static”,或冠以关键字“extern”,表示此函数是外部函数:  [extern]&函数类型&函数名(函数参数表)  {……}  调用外部函数时,需要对其进行说明:  [extern]&函数类型&函数名(参数类型表)[,函数名2(参数类型表2)……];
继续阅读>>
热门关键词

我要回帖

更多关于 王者荣耀体验服免费号 的文章

 

随机推荐