根据IEEE 754标准,规定浮点数有float和double两种编码方式,基本格式为:
> 符号数 | 阶码数 | 尾数
float 单精度,长度4个字节,最高位符号位,接下来8位为指数,低23位为位数。
double 双精度,长度8个字节,最高位符号位,接下来11位为指数,低52位为位数。
由于大多数小数无法用精确的二进制表示,所以会出现精度丢失的情况。如,
System.out.println(0.05 + 0.01);
result: 0.060000000000000005
System.out.println(1.0 - 0.42);
result:0.5800000000000001
System.out.println(4.015 * 100);
result:401.49999999999994
System.out.println(123.3 / 100);
result:1.2329999999999999
[解决方案]
使用BigDecimal类
BigDecimal是Java提供的一个不变的,任意精度的,有符号十进制数对象。
1、获取BigDecimal对象
为了实现精确计算,有以下几种方法获得BigDecimal对象:
//使用参数为String类型的构造方法
BigDecimal bigDecimal1 = new BigDecimal ("0.01");
//将double转换为String后,利用构造方法获得
BigDecimal bigDecimal2 = new BigDecimal (Double.toString(0.05));
//使用静态方法,内部实现还是先将double转换为了String
BigDecimal bigDecimal3 = BigDecimal.valueOf(0.01);
注:直接将double类型作为参数利用构造方法获得的BigDecimal对象也是不精确的。
2、方法介绍
[ 获取小数点后位数 ]
int scale()
Returns the scale of this BigDecimal.
注:涉及到无限小数的点后位数时,一定要使用有RoundingMode(舍入模式)的方法,否则在精确小数时无法使用精确模式导致报错。
[ 设置小数点后位数,精确小数 ]
> BigDecimal setScale(int newScale)
BigDecimal setScale(int newScale, int roundingMode)
或者BigDecimal setScale(int newScale, RoundingMode roundingMode)
Returns a BigDecimal whose scale is the specified value, and whose value is numerically equal to this BigDecimal's. Throws an ArithmeticException if this is not possible.
第一个方法设置的小数点后位数小于当前的小数点后位数的话,程序将会报错,应该采用指定舍入模式的方法
[ 精确的加法 ]
BigDecimal add(BigDecimal augend)
Returns a BigDecimal whose value is (this + augend), and whose scale is max(this.scale(), augend.scale()).
[ 精确的减法 ]
BigDecimal subtract(BigDecimal subtrahend)
Returns a BigDecimal whose value is (this - augend), and whose scale is max(this.scale(), augend.scale()).
[ 精确的乘法 ]
BigDecimal mutiply(BigDecimal mutiplicand)
Returns a BigDecimal whose value is (this * mutiplicand), and whose scale is (this.scale() + mutiplicand.scale()).
[ (相对)精确的除法 ]
如果商本身是有限的,那么除法将消除精度丢失,而如果商本身是无限的,那么采用舍入模式实现相对精确.
> BigDecimal divide(BigDecimal divisor)
Returns a BigDecimal whose value is (this / divisor), and whose preferred scale is (this.scale() - divisor.scale()); if the exact quotient( 商 ) cannot be represented (because it has a non-terminating decimal expansion) an ArithmeticException is thrown.
不太能理解preferred scale.
> BigDecimal divide(BigDecimal divisor, int roundingMode)
或者BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode)
Returns a BigDecimal whose value is (this / divisor), and whose scale is this.scale().
采用指定的舍入模式
> BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
或者BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
Returns a BigDecimal whose value is (this / divisor), and whose scale is as specified.
采用指定的舍入模式
[ 舍入模式 ] 有2种,一种是RoundingMode的枚举类,一种是BigDecimal的常量值。以RoundingMode类对象为例
> static RoundingMode CEILING
Rounding mode to round towards positive infinity.
向正无穷方向舍入
> static RoundingMode DOWN
Rounding mode to round towards zero.
向零方向舍入
> static RoundingMode FLOOR
Rounding mode to round towards negative infinity.
向负无穷方向舍入
> static RoundingMode HALF_DOWN
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5
> static RoundingMode HALF_EVEN
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
以下参考自:数字修约规则
商业计算的舍入模式通常使用这个,也叫做四舍六入五留双规则或者Bank's Rounding,更应该叫做四舍六入逢五无后则留双,规则如下:
# 尾数小于等于4时,舍弃;尾数大于等于6时,将尾数舍去并向前一位进位。
# 尾数等于5时,当尾数后面的数字均为0时,如果尾数前一位为奇数,尾数舍去向前一位进位,如果为偶数,直接舍弃(此时0为偶数);如果尾数后面的数字任意一位不为0,直接向前进位。
如,1.050,保留1位有效数字为1.0
1.150,保留1位有效数字为1.2
1.0501,保留1位有效数字为1.1
> static RoundingMode HALF_UP
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6
> static RoundingMode UNNECESSARY
Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
计算结果是精确的,不需要舍入模式
> static RoundingMode UP
Rounding mode to round away from zero.
向远离0的方向舍入
另外,利用数学计算也可以实现小数点后精确位的四舍五入。
/**
* 实现小数点后scale的四舍五入
*
* @param value
* 数值
* @param scale
* 精确到小数点后位数
* @return 四舍五入结果
*/
public static double round(double value, int scale) {
double temp = 1;
for (int i = 0; i < scale; i++) {
temp = temp * 10;
}
return ((int) (value * temp + 0.5)) / temp;
}
System.out.println(round(0.61125, 3));
result: 0.611
相关推荐
c语言浮点数高精度加法计算
关于浮点数的精度问题,对于了解和学习C语言有一定帮助
给大家介绍了Java中浮点数精度问题的解决方法,本文给大家介绍的非常详细,有问题描述有原因分析,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧
单精度浮点数,双精度浮点数,浮点数是属于有理数中某特定子集的数的数字表示,在计算机中用以近似表示任意某个实数。
Java输入浮点数分别输出整数部分和小数部分
java 浮点数举例java 浮点数举例java 浮点数举例
NULL 博文链接:https://spiritfrog.iteye.com/blog/602147
浮点数转换器,可将浮点数、单精度 双精度的数值转换为16进制发送
本代码将双精度浮点数转换为单精度浮点数,适合浮点数为正值的转换。 使用后将占用VD2810~VD2970字节,欢迎交流。 本代码的完成经历了一段时间的刻苦研究,无偿提供给真正需要的人,希望同行少走弯路。 代码允许复制...
本文主要介绍了JAVA浮点数计算精度损失底层原理与解决方案。具有很好的参考价值,下面跟着小编一起来看下吧
该案例演示了浮点数的应用
疯狂java讲义里的课后题,自己编写的程序
用java从文件中读取浮点数 已经亲自实践过,没有问题
目前支持二进制浮点数的硬件和软件文档中,几乎都声称其浮点数实现符合IEEE 754标准。那么,什么是IEEE 754标准? 最权威的解释是IEEE754标准本身ANSI/IEEE Std 754-1985《IEEE Standard for Binary Floating-Point...
C语言中浮点数精度问题分析.pdf
浮点数和十六进制数的相互转换,包括:1.单精度浮点数(32位)和十六进制数的相互转换,2.双精度浮点数(64位)和十六进制数的相互转换。
[Java]IEEE754浮点数的转换方法,方法都写好了,直接复制过去就可以用了,就这么简单!
Java对浮点数的计算是不精确的,比如0.05+0.01结果不是0.06,而是0.060000000000000005,更有甚者,一个数除以0.0,Java是不会抛异常,而是得出无穷大的结果.本工具类解决了上述问题.该类提供了加减乘除四则运算的精确计算...
Java源码获取浮点数类型的最大最小值
对S7-200PLC双精度浮点数转单精度浮点数例程的一点补充,远程抄表相关技术的交流