平方根的C语言实现(一)
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7203254.html 作者:窗户 QQ:6679072 E-mail:6679072@qq.com
曾经做一个硬件成本极度控制的项目,因为硬件成本极低,并且还需要实现较高的精度测量,过程中也自己用C语言实现了正弦、余弦、反正切、平方根等函数。
以下,无论是在我的实际项目中还是本地的计算机系统,int都是4个字节且机器为小端,除非特别提及,否则都如此默认。按理float的存储没有大小端之分,可是的确在powerpc大端上浮点数的存储也一样是和X86/ARM这样的小端机相反。不过因为正好因大小端而决定浮点数的存储顺序,那么本系列贴子里所有的C语言程序至少在powerpc大端上也是效果相同的。
尽管在这个项目中我非常想用double来存储小数,但因为这需要翻一倍的存储,从而只好作罢,为了那可怜的存储,我一度甚至想考虑实现3字节的浮点数来,但大致估算了误差(至于如何估算一个公式计算的误差,需要先利用浮点数的结构求自变量的误差,然后要用到数值分析求公式误差,以后有机会开贴单说),实在不靠谱,于是还是用float单精度4字节来存储浮点数。此项目后面围绕着精度、运算时间,从而调整了好几次数据产生、乃至算法的原理,不过这都不是这个系列里要讲的。本系列只讲单精度4字节浮点数的平方根实现,一共分为三节:
第一节讲浮点数的存储;
第二节讲手算平方根的原理;
第三节讲C语言最终实现。
我们先看浮点数是如何表示实数的,IEEE 754定义了浮点数的结构:
在了解浮点数的存储之前,我们了解一下科学计数法。
我们平常用的进位制为十进制,所有不为0的实数都可以表示为s*a*10n,其中:s取1或-1,称为符号部分;a满足1≤a<10,称为小数部分;n为整数,称为指数部分。
我们的计算机计数一般使用二进制,其道理不用我多说,浮点数也一样用的二进制,用的是二进制下的科学计数法。仿照之前十进制下的科学计数法,即可得二进制下的科学计数。所有不为0的实数,都可以表示为s*a*10n,其中:s取1或-1,称为符号部分;a满足1≤a<2,称为小数部分;n为整数,称为指数部分。32个bit中,最高位1个bits表示符号位s,紧接着的8个bits表示指数位,最后的23个bits表示a。
S(1bits) | N(8bits) | A(23bits)
用大写表示,代表二进制,与科学计数法的s/n/a关系如下:
若S为0,则s取1;若S为1,则s取-1。
n = N(2) - 127,这里N(2)是N的二进制值,
在符号不会混乱的时候,下面就用N来代替N(2)
a = 1 + A(2)*2-23 ,这里是A的二进制值,
在符号不会混乱的时候,下面就用A来代替A(2)
浮点数和定点数一样,也是离散的,4字节浮点数有32个bits,所以最多只能表示232个不同的实数,是对实数的一种近似,但却有很大的范围,可以满足我们很多的需求了。
写一个C语言程序来验证这点:
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
int main(int argc, char **argv)
{
union {
float f;
uint32_t u;
} n;
int i; scanf("%f", &n.f);
for(i=31;i>=0;i--) {
if(n.u&(1u<<i))
printf("1");
else
printf("0");
if(i==31 || i==23)
printf(" ");
}
printf("\n");
printf("S:%u\n", (n.u&(1u<<31))>>31);
printf("N:%u\n", (n.u&(0xff<<23))>>23);
printf("A:%u\n", n.u&0x7fffff);
return 0;
}
随便找几个数验证一下
$ echo | ./a.out S:
N:
A:
$ echo - | ./a.out S:
N:
A:
$ echo | ./a.out S:
N:
A:
$ echo | ./a.out S:
N:
A:
$ echo 3.5 | ./a.out S:
N:
A:
$ echo 3.75 | ./a.out S:
N:
A:
$ echo 0.75 | ./a.out S:
N:
A:
$ echo 0.875 | ./a.out S:
N:
A:
上面的数都是满足的。
可是我们再回头看看,科学计数法其实也是有缺陷的,0其实是无法用科学计数法表示的,可是0使用的场合非常多,所以浮点数必须支持。于是单精度浮点数的2^32种表示中,不是每一种都是科学计数法。
IEEE754规定,单精度浮点数还支持非规格化的数,也就是不是科学计数法的数。
当指数位N为0,也就是N的8个bits全是0的时候,符号位依然是符号位,
表示的数值是s* A*2-149,
之所以后面的指数是149,是因为规格化的数所能表示的最小正数为2-126,
而N为0的时候所表示的最大数为(223-1)*2-149,
两者十分接近,
$ echo 'scale=60;2^(-126);(2^23-1)*2^(-149);' | bc
.
.
编个C语言程序验证一下
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
int main(int argc, char **argv)
{
union {
float f;
uint32_t u;
} n;
int i; scanf("%" PRIx32, &n.u);
for(i=31;i>=0;i--) {
if(n.u&(1u<<i))
printf("1");
else
printf("0");
if(i==31 || i==23)
printf(" ");
}
printf("\n");
printf("S:%u\n", (n.u&(1u<<31))>>31);
printf("N:%u\n", (n.u&(0xff<<23))>>23);
printf("A:%u\n", n.u&0x7fffff);
printf("%.60f\n", n.f);
return 0;
}
找几个数验证一下
$ echo 0x00000001 | ./a.out S:
N:
A:
0.000000000000000000000000000000000000000000001401298464324817
$ echo 0x007fffff | ./a.out S:
N:
A:
0.000000000000000000000000000000000000011754942106924410754870
$ echo 0x80000001 | ./a.out S:
N:
A:
-0.000000000000000000000000000000000000000000001401298464324817
$ echo 0x807fffff | ./a.out S:
N:
A:
-0.000000000000000000000000000000000000011754942106924410754870
$ echo 0x00000000 | ./a.out S:
N:
A:
0.000000000000000000000000000000000000000000000000000000000000
$ echo 0x80000000 | ./a.out S:
N:
A:
-0.000000000000000000000000000000000000000000000000000000000000
可以看到,有0和-0的区别,浮点数的确就有这么神奇。
另外,IEEE754规定,N等于127,也就是这8个bits全为1的时候也是非规格数,分以下三种情况:
S=0,N=127,A=0时,为正无穷大;
S=1,N=127,A=0时,为负无穷大;
N=127,A≠0是,为NAN(not a number)。
同理,我们还是验证一下:
$ echo 0x7f800000 | ./a.out S:
N:
A:
inf
$ echo 0xff800000 | ./a.out S:
N:
A:
-inf
$ echo 0x7f800001 | ./a.out S:
N:
A:
nan
$ echo 0xff800001 | ./a.out S:
N:
A:
nan
inf和-inf用于两个实数通过运算产生,因其大小上已经超越浮点数最大可程度以表示的实数,只能用无穷大表示,或者浮点数除0。
而nan则是结果已经不是实数范畴了,比如inf参与了运算,再比如,负数开平方根也会产生nan,这是因为浮点数并不是用于直接表示复数,浮点数并非是要直接模拟一个近似的代数闭包。
平方根的C语言实现(一)的更多相关文章
- 平方根的C语言实现(三) ——最终程序实现
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7223254.html 作者:窗户 Q ...
- 平方根的C语言实现(一) —— 浮点数的存储
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7203254.html 作者:窗户 Q ...
- 平方根的C语言实现(二) —— 手算平方根的原理
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7220506.html 作者:窗户 Q ...
- 使用牛顿迭代法和二分法求解一个数的平方根(python语言实现)
#牛顿迭代法 def sqrt1(x): y = 1.0 while abs(y * y - x) > 1e-6: y = (y + x/y)/2 return y #使用二分法 def sqr ...
- 皮尔逊相似度计算的例子(R语言)
编译最近的协同过滤算法皮尔逊相似度计算.下顺便研究R简单使用的语言.概率统计知识. 一.概率论和统计学概念复习 1)期望值(Expected Value) 由于这里每一个数都是等概率的.所以就当做是数 ...
- 皮尔森相似度计算举例(R语言)
整理了一下最近对协同过滤推荐算法中的皮尔森相似度计算,顺带学习了下R语言的简单使用,也复习了概率统计知识. 一.概率论和统计学概念复习 1)期望值(Expected Value) 因为这里每个数都是等 ...
- C语言之linux内核实现平方根计算算法
关于平方根的计算,在linux内核中也有实现,就像math.h数学库里的sqrt这个函数一样. 平方根的公式定义: 如果一个非负数x的平方等于a,即 , ,那么这个非负数x叫做a的算术平方 ...
- Leecode刷题之旅-C语言/python-69x的平方根
/* * @lc app=leetcode.cn id=69 lang=c * * [69] x 的平方根 * * https://leetcode-cn.com/problems/sqrtx/des ...
- C语言之基本算法11—牛顿迭代法求平方根
//迭代法 /* ================================================================== 题目:牛顿迭代法求a的平方根!迭代公式:Xn+1 ...
随机推荐
- Spring+SpringMVC+MyBatis深入学习及搭建(十)——MyBatis逆向工程
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6973266.html 前面讲到:Spring+SpringMVC+MyBatis深入学习及搭建(九)--My ...
- 【数据库】Mean web开发 03-MongoDB客户端管理工具NoSQL Manager for MongoDB的使用
简介 Mean是JavaScript的全栈开发框架.更多介绍 用MongoDB实现持久数据的存储是Mean Web全栈开发中的一部分. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非 ...
- 同是办公软件,wps和office有什么区别?
今天完美小编为大家带来的是wps和office有什么区别教程,那么到底有什么区别呢?相信很多朋友都模棱两可,说不出所以然,看看下面的教程,相信你会选择更适合你的那一款软件.一起来看看吧! 1.两者特点 ...
- Nmap脚本引擎原理
Nmap脚本引擎原理 一.NSE介绍 虽然Nmap内嵌的服务于版本探测已足够强大,但是在某些情况下我们需要多伦次的交互才能够探测到服务器的信息,这时候就需要自己编写NSE插件实现这个功能.NSE插件能 ...
- Ubuntu上使用Web QQ
Linux下的pidgin已经不支持QQ了,只能用Web QQ了.Firefox应用市场(Firefox Marketplace)中有一款QQ的Web应用,比你打开浏览器输入网址用得稍微方便点.不 ...
- java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleExcept问题解决方案
在部署Dynamic Web Project时,如果正确配置web.xml或者标注时,仍然出现以上异常的话,可以尝试以下内容讲解的方法: 首先,双击eclipse中的servers,位置如下图&quo ...
- python 标准库 -- re
re 正则表达式 语法 import re m = re.search('[0-9]','abc4def67') # 匹配字符及匹配范围 print m.group(0) # 返回匹配结果 re.se ...
- 【Python3之面向对象进阶】
一.isinstance和issubclass 1.isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object): pass obj=Foo() p ...
- html与xhtml有什么区别?
HTML与XHTML之间的差别,主要分为功能上的差别和书写习惯的差别两方面. 关于功能上的差别,主要是XHTML可兼容各大浏览器.手机以及PDA,并且浏览器也能快速正确地编译网页. 由于XHTML的语 ...
- supervisor 安装配置
Supervisor介绍 Supervisor 允许其用户在UNIX类操作系统上控制多个进程. 块如下: 方便 需要为每个进程实例编写rc.d脚本通常是不方便的. rc.d脚本是进程初始化/自动启动/ ...