浮点数是什么?
- 翻译: 浮点类型是float和double,它们在概念上与单精度32位和双精度64位格式IEEE 754的值和操作相关,这些值和操作在ANSI/IEEE标准754-1985 (IEEE,纽约)的二进制浮点运算IEEE标准中指定.
- 出处: The Java Language Specification, Java SE 8 Edition
由其Java版定义可只,为float,double型,并且相关标准由IEEE指定,下面会阅读IEEE754文档
浮点型的表示
- 解释: 黄色部分为浮点型表示公式,其上为二进制表示形式,由三部分组成
S
(符号位),Exponent
(指数),Fraction
(小数),而Exponent,Fraction在single(单精度即float),double(双精度即double)下分别有不同最大位数. - significand: 表示尾数,由
1.
和Fraction
组成,图中说明了尾数的范围 - 出处: IEEE 754 FLOATINGPOINTREPRESENTATION
计算浮点型的二进制表示形式
- 计算整数部分二进制表示形式
- 计算小数部分二进制表示形式(不同整数部分计算方法,采用×2顺序取整数部分)
- 移动小数点到左起第一个有效位右边,移动多少位就乘以2的多少次方
- 指数转换成Exponent(即实际指数+127或者1203)
eg:
(字丑,献丑了0.0)
计算浮点型的二进制科学计数表示形式
- 计算整数部分二进制表示形式
- 计算小数部分二进制表示形式(不同整数部分计算方法,采用×2顺序取整数部分)
- 移动小数点到左起第一个有效位右边,移动多少位就乘以2的多少次方
浮点型为什么是不精确的?
- 前言: 由浮点型的计算机表示形式可只,是由一个小数与一个以2为底的指数相乘的结果
- 分析:
- 因为Exponent是一个整数,若尾数确定,该公式可表示为f(n)=s*2^n,该函数是一个不连续函数,所以会有很多点是通过无限趋近的近似表示.
- 推测: 为了节省表示浮点数的空间而采用了2进制科学计数法表示浮点数,但是失去了精度
Java中什么时候会丢失精度?
- 前言: 前面所做分析是基于浮点型的规范,没有具体场景.
- 验证
- 单独打印2.3f是否会丢失精度,是否会表示成计算机表示形式?
- 结果: 没有丢失精度
- 计算1.1f+1.2f是否会丢失精度?
- 结果: 丢失了精度,表示为计算机表示形式了
- 计算2.0f+0.3f是否会丢失精度
- 结果: 没有丢失精度
- 单独打印2.3f是否会丢失精度,是否会表示成计算机表示形式?
- 推论:
若按浮点型规范文档所述,无论我们计算还是直接打印2.3f应该都会丢失精度,那为什么直接打印和与一个整数相加没有丢失精度?我猜测是Java编译器做了特殊处理:- 若浮点型没有参数运行,在从计算器取出时会自动根据其实际精度进行舍入处理(编译器记录精度)
- 若两个浮点型参与运算,编译器不会做多的处理,表示形式即为计算机表示形式
- 若一个整数和一个浮点型运行,结果的精度为浮点型的精度
使用场景
浮点型由于其在运算中有一定可能会丢失精度,所以建议用于对精度丢失可容忍的场景,比如,游戏伤害数值,货币体系中最好不要用浮点型.
结语
以上推论未经实际验证(可能需要深入JVM查看编译器代码),若理论有误,望指正.
参考文献
The Java Language Specification, Java SE 8 Edition
IEEE 754 FLOATINGPOINTREPRESENTATION