计算机中关于数字的一切问题的核心:计算机中用二进制来表示十进制的整数和浮点小数。
——蓝萨节
为什么叫浮点小数:
为何叫浮点数呢?是指小数点的位置可以移动。为什么需要移动呢,它与计算机中数的表示方法有着密切的关系。
计算机本来只处理整数,事实上整数也是二进制的比特串。所以,必须要用某种方法,将含有小数部分的数变成二进制的比特串(编码)。
可以考虑用几种方法将小数编码成二进制。具代表性的方法有两种:
一是抬高小数进行整数化;
二是使用科学计数法来表示。
进行整数化使用不广泛,其优点是速度高,其缺点在可能造成浪费,小数位数固定。
因此一般用科学技术法表示。但计算机是用二进制,而不是用十进制来表示数,所以实际上这个数在内部不是以2.5和104来记录的,必须变为二进制的比特串。变为比特串的方式有多种。广泛采用的被称作IEEE754方式。
f称为尾数部分(mantissa),e称为指数部分(exponent)。双精度中,指数部分有11位,可以表示+1023~-1024,也就是可以表示2的1023次方。
尾数部分有52位。IEEE754规定,尾数部分的首位始终归一化3为1,所以首位始终省略4,实质有效数字为53位。
所谓归一化就是将尾数部分变成大于等于1,小于2的数。比如想表示48,可以用3×2^4表示,但必须写成1.5×2^5的形式。
科学计数法表示浮点小数的问题:
小数不能完全表示:
除了与整数一样有表示范围的限制外,小数还有更复杂的情况,他们是
除不尽的小树无法完全表示
十进制可以除尽的数二进制是除不尽的。
比如看下面一个程序:
我们看到0.1加10次不等于1.0,这是因为0.1在现实中是一个精确的数,但在计算机中用二进制表示的时候,只能用一个近似值来表示,我们看到加了十次后,误差有1.110223e-16那么大。这就造成了浮点数有误差。我们关于浮点数有几条铁律。
关于使用浮点数的几条铁律:
铁则一,两个浮点数不能用==进行比较。如果有进行比较的必要,判断条件中两个数的差要写得足够小。这个数在Ruby中是Float::EPSILON,其值为2.22044604925031e-16。
铁则二:减少运算次数。比如例子中乘以10,就比加十个0.1误差小。
铁则三:为了避免信息丢失,需要在计算顺序方面想办法,最基本的是要避免特大数和特小数之间的运算。
铁则四:对于浮点小数,结合法不成立。因为结合法会扩大误差。
浮点数运算的陷阱可以归结为两个原因:一是能够表示的精度有限,二是以二进制表示。
解决浮点数误差的两个方法:
ruby语言中提供了BigDecimal类和能表示分数的Rational类。
IEEE754还定义了几个特别的“数”
无限大:用来表示溢出错误。
零:零有符号,有正负之分。
NaN:not a number 表示非数,比如0/0,为了表示未定义的结果错误。
閱讀更多 黑客小學生藍薩節 的文章