程序员必知之浮点数运算原理详解 - Go语言中文社区

程序员必知之浮点数运算原理详解


程序员必知之浮点数运算原理详解

  导读:浮点数运算是一个非常有技术含量的话题,不太容易掌握。许多程序员都不清楚使用==操作符比较float/double类型的话到底出现什么问题。 许多人使用float/double进行货币计算时经常会犯错。这篇文章是这一系列中的精华,所有的软件开发人员都应该读一下。

  随着你经验的增长,你肯定 想去深入了解一些常见的东西的细节,浮点数运算就是其中之一。

1. 什么是浮点数?

  在计算机系统的发展过程中,曾经提出过多种方法表达实数。

  【1】典型的比如相对于浮点数的定点数(Fixed Point Number)。在这种表达方式中,小数点固定的位于实数所有数字中间的某个位置。货币的表达就可以使用这种方式,比如 99.00 或者 00.99 可以用于表达具有四位精度(Precision),小数点后有两位的货币值。由于小数点位置固定,所以可以直接用四位数值来表达相应的数值。SQL 中的 NUMBER 数据类型就是利用定点数来定义的。

  【2】还有一种提议的表达方式为有理数表达方式,即用两个整数的比值来表达实数。

  定点数表达法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数。最终,绝大多数现代的计算机系统采纳了所谓的浮点数表达方式

  【3】浮点数表达方式, 这种表达方式利用科学计数法来表达实数,即用一个尾数(Mantissa ),一个基数(Base),一个指数(Exponent)以及一个表示正负的符号来表达实数。比如 123.45 用十进制科学计数法可以表达为 1.2345 × 102 ,其中 1.2345 为尾数,10 为基数,2 为指数。浮点数利用指数达到了浮动小数点的效果,从而可以灵活地表达更大范围的实数。提示: 尾数有时也称为有效数字(Significand)。尾数实际上是有效数字的非正式说法。

  同样的数值可以有多种浮点数表达方式,比如上面例子中的 123.45 可以表达为 12.345 × 101,0.12345 × 103 或者 1.2345 × 102。因为这种多样性,有必要对其加以规范化以达到统一表达的目标。规范的(Normalized)浮点数表达方式具有如下形式:

  d.dd...d × βe , (0 ≤ di < β)

  其中 d.dd...d 即尾数,β 为基数,e 为指数。尾数中数字的个数称为精度,在本文中用 p(presion) 来表示。每个数字 d 介于 0 和基数β之间,包括 0。小数点左侧的数字不为 0。

(1)  基于规范表达的浮点数对应的具体值可由下面的表达式计算而得:(p是精度个数)

  ±(d0 + d1β-1 + ... + dp-1β-(p-1)e , (0 ≤ di < β)

  对于十进制的浮点数,即基数 β 等于 10 的浮点数而言,上面的表达式非常容易理解,也很直白。计算机内部的数值表达是基于二进制的。从上面的表达式,我们可以知道,二进制数同样可以有小数点,也 同样具有类似于十进制的表达方式。只是此时 β 等于 2,而每个数字 d 只能在 0 和 1 之间取值。

(2)  比如二进制数 1001.101 相当于:精度为7

   1 × 2 3 + 0 × 22 + 0 × 21 + 1 × 20 + 1 × 2-1 + 0 × 2-2 + 1 × 2-3,对应于十进制的 9.625。

  其规范浮点数表达为 1.001101 × 23

(3)  IEEE (美国电气和电子工程师学会)浮点数

  计算机中是用有限的连续字节保存浮点数的。

  IEEE定义了多种浮点格式,但最常见的是三种类型:单精度、双精度、扩展双精度,分别适用于不同的计算要求。一般而言,单精度适合一般计算,双精度适合科学计算,扩展双精度适合高精度计算。一个遵循IEEE 754标准的系统必须支持单精度类型(强制类型)、最好也支持双精度类型(推荐类型),至于扩展双精度类型可以随意。单精度(Single Precision)浮点数是32位(即4字节)的,双精度(Double Precision)浮点数是64位(即8字节)的。

  保存这些浮点数当然必须有特定的格式,Java 平台上的浮点数类型 float 和 double 采纳了 IEEE 754 标准中所定义的单精度 32 位浮点数和双精度 64 位浮点数的格式。注意: Java 平台还支持该标准定义的两种扩展格式,即 float-extended-exponent 和 double-extended-exponent 扩展格式。这里将不作介绍,有兴趣的读者可以参考相应的参考资料。

  在 IEEE 标准中,浮点数是将特定长度的连续字节的所有二进制位分割为特定宽度的符号域,指数域和尾数域三个域,其中保存的值分别用于表示给定二进制浮点数中的符号,指数和尾数。这样,通过尾数和可以调节的指数(所以称为"浮点")就可以表达给定的数值了。

  具体的格式参见下面的表格:

  

  需要特别注意的是,扩展双精度类型没有隐含位,因此它的有效位数与尾数位数一致,而单精度类型和双精度类型均有一个隐含位,因此它的有效位数比位数位数多一个。


   

  IEEE754标准规定一个实数V可以用:  V=(-1)s×M×2^E的形式表示,说明如下:
  (1)符号s(sign)决定实数是正数(s=0)还是负数(s=1),对数值0的符号位特殊处理。
  (2)有效数字M是二进制小数,M的取值范围在1≤M<2或0≤M<1。
  (3)指数E(exponent)是2的幂,它的作用是对浮点数加权。


   为了强制定义一些特殊值,IEEE标准通过指数将表示空间划分成了三大块:

  【1】最小值指数(所有位全置0)用于定义0和弱规范数

  【2】最大指数(所有位全值1)用于定义±∞和NaN(Not a Number)

  【3】其他指数用于表示常规的数

  这样一来,最大(指绝对值)常规数的指数不是全1的,最小常规数的指数也不是0,而是1。

   版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_30883271/article/details/95876129
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

  • 发表于 2020-06-27 23:31:14
  • 阅读 ( 564 )
  • 分类:职场

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢