浮点数

一、概述

       Java虚拟机的浮点数支持符合IEEE0-754 1985浮点标准, 该标准定义了32位和64位浮点数的格式及这些浮点数的运算. 在java虚拟机中, 浮点运算基于32位float类型和64位double类型进行. 每一个执行float类型运算的操作码,都会有一个与之对应的操作码, 该操作码在double类型上实现同样的功能.

       浮点数由符号,尾数,基数和指数四部分组成. 符号位的值要么是1,要么是-1, 尾数永远是一个正数, 它确定浮点数的有效位数. 指数指与尾数,符号相乘的基数的幂的值, 幂值可以为正,也可以为负. 可以用以下公式计算: 符号位与尾数相乘, 然后再乘以基数的指数次幂,即得到所指的浮点数.

       符号 * 尾数 * 基数的指数次幂

      

二、规范化指数

因为同一个浮点数可以表示为多个不同的尾数,基数和指数的组合,所以浮点数可以有多种表示形式. 例如, 数字-5 可以被表示为以下所列的几种形式, 这几种形式都是以10为基数.

符号                          尾数                           基数^指数

-1                               50                               10^-1

-1                               5                                 10^0

-1                               0.5                              10^1

-1                               0.05                            10^2

   

    对于每一个浮点数来说, 都会有一种被称为"规范化"的表示形式. 如果一个浮点数的尾数满足下面所列的关系式,则称这个浮点数为规范化的浮点数.

       1/基数 <= 尾数 < 1

       在以10为基数的浮点数中, 尾数的小数点位置在第一个不为0的数字的左边. 因此, -5的规范化浮点数表示为: -1 * 0.5 * 10^1. 换句话说, 一个规范化浮点数的尾数, 它的小数点左边的数字一定为0, 紧接小数点右边的数字一定不为0. 不符合这条规则的浮点数被称为非规范化的浮点数. 需要注意的是, 因为0在小数点右边没有不为0的数字, 因此数字0没有规范化的表示. 在处理数字0的时候经常会发出这样的感叹" 为什么要规范化??"

       Java虚拟机中浮点数使用2为基数, 因此, 它们可以表示为如下形式:

       符号 * 尾数 * 2的指数次幂

       Java虚拟机中浮点数的尾数使用二进制来表示. 规范化尾数的二进制小数点(基于二进制与十进制中作用相同)在最高有效非0数字的左边. 因为二进制系统只有两个数字 -- 0和1, 所以, 对于规范化尾数来说, 最高有效的数字就是1.

       对于float类型或者double类型来说, 符号位是最高有效位. 尾数在float类型中占最低有效位的23位, 在double类型中占最低有效位的52位. 指数位于符号和尾数之间, 它在float类型中占8位, 在double类型中占11位. float类型的格式如下所示, 符号位表示为s, 指数位表示为e, 尾数位表示为m

       31 30~23      22~0   

       s  eeeeeeee mmmmmmmmmmmmmmmmmmmmmm

       符号位为0, 表示正数; 符号位为1, 表示负数. 尾数通常表示为二进制正数.它并不是二进制补码数. 如果符号位为1, 浮点数的值为负, 但是尾数仍然表示为正数, 但是如果要表示浮点数的值,就需要乘上-1.

       指数位的解释有三种方式. 指数位全为1, 表示该数为乘法或者减法所产生的特殊值之一 -- 无穷大或者非数字(NaN Not a Number), NaN是某种特殊操作,诸如0除以0的结果, 指数位均为0, 表示该数是一个非规范化浮点数. 其他类型的指数位均表示该数为一个规范化的浮点数.

       尾数区域包含一位附加精度位, 它不同于尾数中的其他位的作用. float类型的尾数只占据23位, 但它有24位精度.double类型的尾数占据52位,但它有53位精度. 由于Java虚拟机的浮点数的指数指明该数是否是规范化的, 尾数中的最高有效位是可以预知的,因此没有被划入位数的范围. 如果指数位全为0, 那么该数为非规范化的浮点数, 可知尾数的最高有效位为0. 否则, 浮点数是规范化的,那么尾数的最高有效位为1.

       Java虚拟机在任何浮点数操作中均不抛出异常. 特殊值(例如正无穷大,负无穷大或者NaN)作为可疑操作(比如除0)的结果返回. 指数位全为1, 表示特殊的浮点值. 指数位全为1而且尾数全为0,表示无穷大. 无穷大的符号由符号位表示出来.指数位全为1,尾数位不全为0, 表示该数为NaN. Java虚拟机总是为NaN产生同样的尾数:除了尾数中最高有效位为1外,其余各位均为0. float类型的这些特殊值如下所示:

       值                                                    浮点位(符号 指数 尾数)

       +无穷                                              0 11111111 0000000000000000000000

       -无穷                                               1 11111111 0000000000000000000000

       NaN                                                 1 11111111 1000000000000000000000

      

       如果指数位既不全为0,又不全为1, 该数即为规范化的浮点数. 可以通过把指数位看作是一个正数, 然后从这个正数中减去一个偏移量的方法来确定2的幂指数. 对于float类型, 偏移量为127. 对于double类型, 偏移量为1023. 例如, 一个浮点数的指数区域为00000001, 那么它的幂指数可以通过如下步骤得到: 把指数区域看作是一个正整数(1), 然后减去偏移量(127), 然后就可以得到2的幂指数为1-127=-126. 这个值是float类型的的2的幂指数的最小值. 另外,指数区域为11111110的2的幂指数为(254-127),即为127. 127是float类型的最大的2的幂指数.

       指数位全为0表示尾数非规范化, 这意味着未指明的最重要位的值为0,而不是1. 此时2的幂指数与规范化尾数的2的幂指数最小值相等. 对于float类型, 该值为-126. 与2的-126次幂相乘的规范化尾数, 其指数区域为00000001;而与2的-126次幂相乘的非规范化尾数,其指数区域为00000000.

       指数范围底端的非规范化浮点数允许渐进的下溢. 如果这个最小的指数用来描述规范化数,那么一些较大的数将会下溢至0. 换句话说, 指定了非规范化数最小指数使得描述一些更小的数成为可能. 这些更小的数与那些规范化数相比较, 它们的精度较低, 但是这样可以有效地解决指数一旦达到规范化最小值,就会下溢至0的问题.

三、其他:

       所有浮点数取余操作都不会导致异常抛出. 任何值除以0的取余操作都会得出NaN的结果. 关于无穷大, 0, NaN和有限值之间的多种组合的取余结果如下所示:

 

       a                          b                          a/b                              a%b

       有限值                +-0.0                    +-无限值                    NaN

       有限值                +=无限值            +-0                              a

       +-0.0                    +-0.0                    NaN                            NaN

       +-无限值             有限值                +-无限值                    NaN

       +-无限值             +无限值                     NaN                            NaN

四、参考(Float中的关于浮点数的处理)

       演示了从4个字节的数据中还原一个float

float bytesToFloat(byte[] bytes) {

       // 用一个联合,实现浮点数float和int的共用体

       union {

        int i;

        float f;

    } u;

 

    /* do conversion */

   

    int ival =    ((bytes[srcpos + 0] & 0xFF) << 24) +

               ((bytes[srcpos + 1] & 0xFF) << 16) +

               ((bytes[srcpos + 2] & 0xFF) << 8) +

               ((bytes[srcpos + 3] & 0xFF) << 0);

    u.i = ival;

    return u.f;

}

 

 

本教程由尚硅谷教育大数据研究院出品,如需转载请注明来源。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值