Java 浮点数的范围和精度
本篇先介绍IEEE754标准中针对浮点数的规范,然后以问答形式补充有关浮点数的知识点。
(一)IEEE754标准
IEEE 754 标准即IEEE浮点数算术标准,由美国电气电子工程师学会(IEEE)计算机学会旗下的微处理器标准委员会发布。
以32位float数据为例,在内存中的存储形式是1bit的符号位(S),8bit表示指数部分(Exp),23表示小数部分的尾数(Fraction)。
表一 单精度浮点数在内存中存储形式
|
1bit符号 |
8bit指数部分 |
23bit尾数 |
符号位——S取0时表示负数,取1时表示负数。
指数部分——使用所谓的偏正值形式表示,而不是补码表示,即指数部分采用一个无符号的正数值存储。也就是说指数部分要表示的值等于实际存储值减去一个固定值(对于单精度float类型,是127)。采用这种方式表示的目的是简化比较,因为,如果采用补码表示的话,全体符号位S和Exp自身的符号位将导致不能简单的进行大小比较。因为指数值的大小从0~255(0和255是特殊值),单精度的指数部分范围是-127~+128(对应的,-127和128是特殊值)。
尾数部分——23bit尾数仅能表示小数部分的尾数,小数部分最高有效位由指数部分决定,具体见下表。小数部分最高有效位是1的数被称为正规形式。小数部分最高有效位是0的数被称为非正规形式,其他情况是特殊值。
表二 单精度浮点数表示规则
|
符号 |
指数 部分 |
指数部分-127 |
尾数部分 |
小数部分的 最高有效位 |
形式 |
|
1 |
255 |
128 |
非0 |
没有 |
NaN |
|
1 |
255 |
128 |
0 |
没有 |
负无穷 |
|
1 |
1~254 |
-126~127 |
任意 |
1 |
正规形式(负数) |
|
1 |
0 |
-127 |
非0 |
0 |
非正规形式(负数) |
|
1 |
0 |
-127 |
0 |
没有 |
负0 |
|
0 |
0 |
-127 |
0 |
没有 |
正0 |
|
0 |
0 |
-127 |
非0 |
0 |
非正规形式(正数) |
|
0 |
1~254 |
-126~127 |
任意 |
1 |
正规形式(正数) |
|
0 |
255 |
128 |
0 |
没有 |
正无穷 |
|
0 |
255 |
128 |
非0 |
没有 |
NaN |
按照IEEE标准,除了 NaN 以外,浮点数集合中的所有元素都是有序的。如果把它们从小到大按顺序排列好,那顺序将会是:负无穷,正规形式(负数)、非正规形式(负数)、负0、正0、非正规形式(正数)、正规形式(正数)、正无穷。
对于64bit的双精度double类型,在内存中的存储形式是1bit的符号位(S),11bit表示指数部分(Exp),52bit表示小数部分的尾数(Fraction)。指数部分的偏正值是1023,其他情况跟单精度类似,不再赘述。
(二)浮点数Q&A
1)浮点数可以表示数据的范围是什么?
不考虑特殊值(无穷大、NaN等),浮点数可以表示的范围是[-Max,Max]。其中Max是浮点数能表示的最大值,具体值参见表三。
表三 浮点数最大值
|
浮点类型 |
字节码 |
16进制表示 |
10进制表示 |
|
单精度 |
7f7fffff |
0x1.fffffep127 |
3.4028235E38 |
|
双精度 |
7fefffffffffffff |
0x1.fffffffffffffp1023 |
1.7976931348623157E308 |
2)浮点数的精度怎样衡量?
浮点数指数部分Exp的数值决定了浮点数与相邻浮点数的差值,所以,指数部分越小(单精度最小为-127),即浮点数绝对值越小(也就是浮点数越靠近0),相邻浮点数的差值越小(单精度最小为2^(-127)),浮点数能表示的有效小数位数越多。反之,指数部分越大(单精度最大为127),即浮点数绝对值越大(也就是浮点数越远离0),相邻浮点数的差值越大(单精度最小为2^(127)),浮点数能表示的有效小数位数越少。但是,从科学计算的角度看,不管指数部分的数值是多少,浮点数的有效位数由尾数部分决定,单精度的有效数是7位,双精度的有效数是16位。
表四 浮点数最小正数
|
浮点类型 |
字节码 |
16进制表示 |
10进制表示 |
|
单精度最小正数 |
00000001 |
0x0.000002p-126 |
1.4E-45 |
|
双精度最小正数 |
0000000000000001 |
0x0.0000000000001p-1022 |
4.9E-324 |
3)我们知道,在Java中,存在基本数据类型的自动转换,比如,直接将一个整形字面量赋给一个float变量。 那么,在自动转换后,整形的精度会丢失么?
当浮点集中没有与整形值对应的浮点数时,会将整形值转化成最接近的浮点值,此时,整形值会丢失精度。例如下面的例子,数值为33554431的整形转化成单精度浮点数后,变成3.3554432E7,即33554432。
int intValue = Integer.MAX_VALUE >> 6;// 33554431
float floatFromInt = intValue;
System.out.println(floatFromInt);// 3.3554432E7
System.out.println(intValue);// 33554431
最后附查看某些浮点数字节码、16进制表示、10进制表示的源码及运行结果。
单精度源码及结果。
package com.wsm.test;
public class TestFloat {
/**
* @param args
*/
public static void main(String[] args) {
int intValue = Integer.MAX_VALUE >> 6;//
float floatFromInt = intValue;
System.out.println(floatFromInt);// 3.3554432E7
System.out.println(intValue);//
System.out.printf("%-12s\t%-20s%-12s%-20s\n", "描述", "十六进制数",
" 字节码", " 十进制数");
print("正 无 穷", Float.POSITIVE_INFINITY);
print("最 大 值", Float.MAX_VALUE);
print("最小正规形式正数", Float.MIN_NORMAL);
print("最大非正规形式值", +0x0.fffffep-127f);
print("最 小 正 数", Float.MIN_VALUE);
print("负 无 穷", Float.NEGATIVE_INFINITY);
print("规 范 的 NaN", Float.NaN);
print("其 他 的 NaN", Float.intBitsToFloat(Integer
.valueOf(0xffc54321)));
}
static void print(String describe, float floatNum) {
System.out.printf("%-12s\t%-20s%-12s%-20s\n", describe, Float
.toHexString(floatNum), insertZero(Integer.toHexString(Float
.floatToRawIntBits(floatNum)), 8), floatNum);
}
static String insertZero(String input, int length) {
StringBuilder sb = new StringBuilder(input);
while (sb.length() < length) {
sb.insert(0, "0");
}
return sb.toString();
}
}
Float
3.3554432E7
33554431
描述 十六进制数 字节码 十进制数
正 无 穷 Infinity 7f800000 Infinity
最 大 值 0x1.fffffep127 7f7fffff 3.4028235E38
最小正规形式正数 0x1.0p-126 00800000 1.17549435E-38
最大非正规形式值 0x0.8p-126 00400000 5.877472E-39
最 小 正 数 0x0.000002p-126 00000001 1.4E-45
负 无 穷 -Infinity ff800000 -Infinity
规 范 的 NaN NaN 7fc00000 NaN
其 他 的 NaN NaN ffc54321 NaN
双精度源码及结果。
package com.wsm.test;
public class TestDouble {
/**
* @param args
*/
public static void main(String[] args) {
System.out.printf("%-12s\t%-30s%-24s%-40s\n", "描述", "十六进制数",
" 字节码",
" 十进制数");
print("正 无 穷", Double.POSITIVE_INFINITY);
print("最 大 值", Double.MAX_VALUE);
print("最小正规形式正数", Double.MIN_NORMAL);
print("最大非正规形式值", +0x0.fffffffffffffp-1023d);
print("最 小 正 数", Double.MIN_VALUE);
print("负 无 穷", Double.NEGATIVE_INFINITY);
print("规 范 的 NaN", Double.NaN);
print("其 他 的 NaN", Double.longBitsToDouble(Long
.valueOf(0xfff8000000054321L)));
}
static void print(String describe, Double DoubleNum) {
System.out.printf("%-12s\t%-30s%-24s%-40s\n", describe, Double
.toHexString(DoubleNum), insertZero(Long.toHexString(Double
.doubleToRawLongBits(DoubleNum)), 16), DoubleNum);
}
static String insertZero(String input, int length) {
StringBuilder sb = new StringBuilder(input);
while (sb.length() < length) {
sb.insert(0, "0");
}
return sb.toString();
}
}
Double
描述 十六进制数 字节码 十进制数
正 无 穷 Infinity 7ff0000000000000 Infinity
最 大 值 0x1.fffffffffffffp1023 7fefffffffffffff 1.7976931348623157E308
最小正规形式正数 0x1.0p-1022 0010000000000000 2.2250738585072014E-308
最大非正规形式值 0x0.8p-1022 0008000000000000 1.1125369292536007E-308
最 小 正 数 0x0.0000000000001p-1022 0000000000000001 4.9E-324
负 无 穷 -Infinity fff0000000000000 -Infinity
规 范 的 NaN NaN 7ff8000000000000 NaN
其 他 的 NaN NaN fff8000000054321 NaN
参考资料:
2、《Java虚拟机规范(Java SE 7)》
Java 浮点数的范围和精度的更多相关文章
- Java浮点数float,bigdecimal和double精确计算的精度误差问题总结
(转)Java浮点数float,bigdecimal和double精确计算的精度误差问题总结 1.float整数计算误差 案例:会员积分字段采用float类型,导致计算会员积分时,7位整数的数据计算结 ...
- Java 浮点数精度丢失
Java 浮点数精度丢失 问题引入 昨天帮室友写一个模拟发红包抢红包的程序时,对金额统一使用的 double 来建模,结果发现在实际运行时程序的结果在数值上总是有细微的误差,程序运行的截图: 输入依次 ...
- js,java,浮点数运算错误及应对方法
js,java浮点数运算错误及应对方法 一,浮点数为什么会有运算错误 IEEE 754 标准规定了计算机程序设计环境中的二进制和十进制的浮点数自述的交换.算术格式以及方法. 现有存储介质都是2进制.2 ...
- java浮点数剖析
定点数表达法的缺点在于其形式过于僵硬,固定的小数点位置决定了固定位数的整数部分和小数部分,不利于同时表达特别大的数或者特别小的数.计算机系统采纳了所谓的浮点数表达方式.这种表达方式利用科学计数法来表达 ...
- [ JAVA编程 ] double类型计算精度丢失问题及解决方法
前言 如果你在测试金融相关产品,请务必覆盖交易金额为小数的场景.特别是使用Java语言的初级开发. Java基本实例 先来看Java中double类型数值加.减.乘.除计算式实例: public cl ...
- Java中浮点类型的精度问题 double float
要说清楚Java浮点数的取值范围与其精度,必须先了解浮点数的表示方法与浮点数的结构组成.因为机器只认识01,你想表示小数,你要机器认识小数点这个东西,必须采用某种方法.比如,简单点的,float四个字 ...
- java中float/double浮点数的计算失精度问题(转)
如果我们编译运行下面这个程序会看到什么? public class Test { public static void main(String args[]) { ...
- JAVA浮点数计算精度损失底层原理与解决方案
浮点数会有精度损失这个在上大学的时候就已经被告知,但是至今完全没有想明白其中的原由,老师讲的时候也是一笔带过的,自己也没有好好琢磨.终于在工作的时候碰到了,于是google了一番. 问题: 对两个do ...
- java浮点数精度问题解决方法
基础知识回顾: BigDecimal.setScale()方法用于格式化小数点setScale(1)表示保留一位小数,默认用四舍五入方式 setScale(1,BigDecimal.ROUND_DOW ...
随机推荐
- Liunx centos 系统 修改hostname
1 centos6下修改hostname [root@centos6 ~]$ hostname # 查看当前的hostnmae centos6.magedu.com [root@centos6 ~]$ ...
- hiho #1469 : 福字(dp)
#1469 : 福字 时间限制:6000ms 单点时限:1000ms 内存限制:256MB 描述 新年到了,你收到了一副画.你想找到里面最大的福字. 一副画是一个n × n的矩阵,其中每个位置都是一个 ...
- 解决c#distinct不好用的问题
当一个结合中想根据某一个字段做去重方法时使用以下代码 IQueryable 继承自IEnumerable 先举例: #region linq to object List<People> ...
- 对JS继承的研究--------------引用
问:类继承和原型继承不是同一回事儿吗,只是风格选择而已? 答:不是! 类继承和原型继承不论从本质上还是从语法上来说,都是两个截然不同的概念. 二者之间有着区分彼此的本质性特征.要完全看懂本文,你必须牢 ...
- vue 修饰符sync
从 Vue 2.3.0 起,重新引入了 .sync 修饰符,作为一个编译时的语法糖存在.它会被扩展为一个自动更新父组件属性的 v-on 监听器. 实例: 父组件:<syTree :refillD ...
- ie文件断点续传
一.概述 所谓断点续传,其实只是指下载,也就是要从文件已经下载的地方开始继续下载.在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了.一般断点下载时才用到Range和Content- ...
- Unity3D_(数据)JsonUtility创建和解析Json
Json 百度百科:传送门 LitJson创建和解析Json 传送门 Json数据解析在Unity3d中的应用 传送门 一.使用JsonUnity创建Json using System.Collect ...
- R_针对churn数据用id3、cart、C4.5和C5.0创建决策树模型进行判断哪种模型更合适
data(churn)导入自带的训练集churnTrain和测试集churnTest 用id3.cart.C4.5和C5.0创建决策树模型,并用交叉矩阵评估模型,针对churn数据,哪种模型更合适 决 ...
- 使用oracle删除表中重复记录
(1)使用用rowid方法 查询重复数据:select * from person a where rowid !=(select max(rowid) from person b where a.c ...
- C++入门经典-例5.13-内存安全,被销毁的内存
1:当指针所指向的内存被销毁时,该区域不可复用.若有指针指向该区域,则需要将该指针置为空值(NULL)或者指向未被销毁的内存. 内存销毁实质上是系统判定该内存不是变成人员正常使用的空间,系统也回将它们 ...