Java 浮点数存储标准 IEEE754

简单介绍一下浮点数

Oracle 中用 NUMBER(3, 2) 存储 22.3 会得到什么?

  • it gives you an error stating that value larger than specified precision

NUMBER(3,2) which mean NUMBER(precision, scale) that allows a total of 3 digits, 2 of which are to the right of the decimal point, leaving only one to the left of it. In other words, the largest number that could fit into this column is 9.99.

  • precision: total number of digits
  • scale: number of digits to the right of the decimal point

在 JavaScript 中整数和浮点数都属于 Number 数据类型, 所有数字都是以 64 位浮点数形式储存, 即便整数也是如此;

  • 0.1 + 0.2 = 0.30000000000000004
  • 0.3 - 0.2 = 0.09999999999999998
  • 9.7 * 100 = 969.9999999999999
  • 0.3 / 0.1 = 2.9999999999999996

在 Java 中, 浮点数类型 (float 和 double) 可以保存一定数量的有效数字, 具体取决于数据类型的位数

  • float: 单精度浮点数类型 float 使用 32 位 (4 字节) 来表示, 可以保留大约 6-7 位有效数字
  • double: 双精度浮点数类型 double 使用 64 位 (8 字节) 来表示, 可以保留大约 15-16 位有效数字

Java 的获取 IEEE 754 格式的 2 进制代码

Double d1 = 0.3;
Float f2 = 0.3F;
Long.toBinaryString(Double.doubleToRawLongBits(d1));
Integer.toBinaryString(Float.floatToRawIntBits(f2));
// 因为转化为整型时前导 0 消失,符号位为正时,可能只展示31/62位;

strictfp

已废弃, 仅了解; 现在大多数平台都是 64 位了

Java 关键词 strictfp 是指"strict floating-point" (严格浮点)

strictfp 可以保证浮点数运算的精确性, 而且在不同的硬件平台会有一致的运行结果。

从 Java 2 开始引入, 现在已经废弃 (在 Java17 之后直接调整为始终严格)

一旦使用了strictfp来声明一个类、接口或者方法时,那么所声明的范围内 Java 的编译器以及运行环境会完全依照浮点规范 IEEE-754 来执行。因此如果想让浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,那就可以使用关键字 strictfp 来解决

浮点运算在不同平台、不同编译器中会有微小的差异, 即在不同平台(16/32/64位处理器)上运行类文件时, 可能会出现不同的输出 (浮点值). 这是因为硬件浮点单位在执行运算时使用的是不同的浮点计算方式, 而这些浮点计算方式可能会导致结果的微小差异. 在一些需要精确计算的场景, 这种差异可能会产生重大影响, 因此 Java 引入了 strictfp 关键词来避免这种问题. strictfp 声明表达式严格遵循 IEEE-754 算术规范,限制浮点计算的精度和舍入, 有助于跨平台特性的实现

需要注意的是, 使用 strictfp 关键词会对性能产生一定的影响, 因为它需要使用一种特定的浮点计算方式来进行计算. 因此, 在一些对性能要求比较高的场景下, 以及只读场景下, 应该谨慎使用 strictfp 关键词

strictfp 无法保证高精度,真正的高精度浮点运算应该查看 java.math.BigDecimal

  • strictfp 只能用在具体的地方, 在用于抽象方法会编译错误
    • V 类
    • V 方法
    • V 接口
    • X 接口方法
    • V 抽象类
    • X 抽象方法
static strictfp double sub(double a, double b) {
    return a - b;
}

科学计数法

  • 在科学计数法中, 一个数值通常被表示为 M x 10^N, 其中 M 是一个在 1 到 10 之间的数, 称为尾数 (mantissa), 而 N 是指数(exponent). 指数表示了小数点向左或向右移动的位数
  • 以下是一些示例
1.23E+6:表示 1.23 乘以 10 的 6 次方,即 1,230,000
5.67E-4:表示 5.67 乘以 10 的 -4 次方,即 0.000567
  • 在科学计数法中,E 代表指数(exponent)的意思

标准 IEEE754 介绍

IEEE格式转化步骤

  1. 浮点数转化为2进制式,再用科学计数法;
220.5 decimal = 22.05 X 10^1  decimal
			  = 2.205 X 10^2  decimal
			  = 11011100.1 X 2^0 binary
			  = 1.10111001 X 2^7 binary
			  = 2^7+2^6+2^4+...+2^-1

PS: decimal to binary,对小数位进行 乘 2 取整,顺序排列,直到积中的小数部分为零,或者达到所要求的精度为止 就得到小数位二进制

  1. 由于除数字 (0) 以外,其他数的二进制全是 1 开头,故依据 754 的浮点数表示标准,默认由 1 开头,争取出一位有效数字。

  2. 双精度浮点数由三个部分组成, 符号位 (1)、指数位 (11) 与尾数位 (52), 总共 64 位

  3. float 占 32 位 4 字节、double 占 64 位 8 字节 (以下用 float 举例)

    1. 尾数域, 23 位用来展示有效数字 (去掉首位 1 的)
    2. 指数域, 8 位用来展示指数域 (注意: 没有符号位, 通过减去中间值 127, 来表达正负)
    3. 正负号, 1 位用来展示正负号
    4. 总共: 23 + 8 + 1 = 32 位
      在这里插入图片描述

其他

  1. IEEE 754 把浮点变为无论多少都以 X.XXX 或者 0.XXXXX (数字非常小)
  2. 实际指数有偏移指数; 这因为中间值 127 的存在,指数域存放的值都是有偏移的,直接取出来的为有偏移指数。减去 127 的为实际指数
  3. 指数域专门提出来,全0全1,都在两端,原本是 +127 和 -127. 全0 拿来存 x -> 0 的正数或者负数, 或者 0. 全1 拿来存正无穷大或负无穷大
  4. 绝对值小于某个数就会被 754 认为是非规约数,这是指数域就全为 0 了,尾数域依然可以表达数值;直到 尾数域 为 0。那么代表这个数为 0
  5. 虽然全为 0 时数值为 0, 但是这个 0 有正负,而且 1/0=inf1/-0=-inf (所以它的数学含义是无穷小)

在线展示浮点型

https://devtool.tech/double-type

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值