c语言程序的生命周期:
要在系统上运行程序,每条c语言的语句都必须被其他程序转换为一系列的低级机械语言指令,从源文件.c目标可执行文件的转换是由编译器驱动程序完成,这个转换过程分为四个阶段:
内核不是一个进程,他是系统全部进程所用代码和数据结构的集合
阿姆达尔定律:加速整个系统需要提升系统中相当大部分的速度
浮点数计算:
缘起:
很奇怪、很不解,虽然有过计算机组成原理学习经历,似乎直到他与计算机中数的表示相关,但却不能道出其中的具体缘由。
实在惭愧,查阅相关资料后先整理于下:
要搞清楚其中缘由必须先了解数在计算机中的两种表示方式:定点数(定点小数,定点整数)和浮点数(不用质疑啦,浮点数当然也能表示整数呀)。
整数的表示很简单
重点是小数的表示:
定点小数在表示的过程中,小数点的位置隐含在固定的位置,他的表示形式与定点整数一致,这种表示方式在不超出位制的计算的时候是很准确的,但是表示的范围是很有限,所以大多数编程语言默认情况下都是采用浮点数的形式保存小数,至于整数都是定点形式,对于多数需要你在申明的时候就要确定数据类型的语言,本来你就应该知道这个类型占有几个字节,能表示最大的数是多少以及表示的范围等等,当然整数在科学计数法情况下会采用浮点形式。
浮点形式采用较多的是采用IEEE 754标准去近似表示实数(注意我的用词是近似表示,这里已经能看出其缺陷了),那么IEEE 754标准是如何表示的呢:
S为位符,决定这个数的正负,M为尾数域,e位指数,像不像初中学的科学计数法的形式?
通常情况下:单精度浮点数(float) 32位的,这样分配这些数:s占一位,e占8位,M占23位
双精度浮点数(double) 64位,这样分配
两个注意点:
-
这样的分配下,其实
1.M
部分1.完全是不用存储的,因为最终都要和科学计数法的规定一样把他化成1开头啊。 -
如果按这样的存储,实际上e部分是没有充分利用的,因为指数部分也需要额外的位数来存储符号对吗,于是做了这样一个操作,将所得到的e,在数轴上整体向右到平移,让他只可能是正数或者0:
32位下:我们知道8位的原码e表示,的最小的负数是-127,我们让E=e+127,然后让计算机去存储E不存储e,实际计算的过程中得到最终结果后,在对指数做减法操作,那么在运算过程E不会再有负数了,节省了符号位
64位下同理:
按照科学计算法的思路,似乎是不错的,那这种表示为什么会出现文初看到的问题呢?问题其实就出在这个M身上。
实际上,把十进制的小数转换为2进制时,其实很多情况下是得不到准确值的!
我们来复习一下十进制的小数转换成为二进制是如何做的:
核心就是乘2,取整数部分:
这么一思考,比如0.1-0.9之间,能够准确的转换为2进制的也只有0.5,所以绝大多数小数换二进制后都是需要做相应的近似,按照条件保留小数的位数的,还记得我说过定点小数表示的话,在位数足够情况下进行计算是很精确的吗,是不是想到decimal类型为何被设计出来了呢,又是如何实现的呢?猜的没错,decimal类型就是使用定点数的形式表示小数并进行计算的!
浮点数计算的过程:
对阶:移动小数点,让两者的指数保持一致
尾数运算:两数(1.M)
部分连同符号位一起加减运算
规格化:结果尾数化成1.M
形式
舍入处理:保留尾数,舍入处理,怎么靠近结果怎么来
下面解释文初的问题:
0.1+0.2,在java
中默认情况下是使用double(双精度浮点数)进行存储的,存储过程中,其实就已经丢失了精度,计算的过程中,最后一步舍入处理又丢失了精度,这就是原因。
搞明白了上面的问题,知道在计算机中0.1+0.2!=0.3,那么下面0.11+0.21==0.32这个计算结果是true还false呢?肯定有很多人会回答false但其实这个结果是true
很奇怪,其实是我们低估了java
的聪明程度,在进行计算的时候java
会选择最近的数进行舍入,仔细想想如果这些都能算错,那java
或者那些语言可太没用了。只是恰巧0.1+0.3在舍入的时候这个后面的尾数比较大而已,不信的话可以复制这个结果在中间加个0,像这样是不是就变成0.3了!