`
QI程序猿
  • 浏览: 17812 次
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java中浮点数丢失精度的解决方案

 
阅读更多

根据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.

采用指定的舍入模式

 

[ 舍入模式 ]

> static int ROUND_CEILING

Rounding mode to round towards positive infinity.

向正无穷方向舍入

 

> static int ROUND_DOWN

Rounding mode to round towards zero.

向零方向舍入

 

> static int ROUND_FLOOR

Rounding mode to round towards negative infinity.

向负无穷方向舍入

 

> static int ROUND_HALF_DOWN

Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.

向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5

 

> static int ROUND_HALF_EVEN

Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.

向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP ,如果是偶数,使用ROUND_HALF_DOWN

 

> static int ROUND_HALF_UP

Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.

向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6

 

> static int ROUND_UNNECESSARY

Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.

计算结果是精确的,不需要舍入模式

 

> static int ROUND_UP

Rounding mode to round away from zero.

向远离0的方向舍入

分享到:
评论

相关推荐

    JAVA浮点数计算精度损失底层原理与解决方案

    总结来说,Java中的浮点数计算精度损失是由浮点数的二进制表示方式决定的,而要解决这个问题,最有效的方法是使用`BigDecimal`类进行高精度计算。在编程时,应根据实际需求选择合适的数值类型和计算策略,确保计算...

    Java中实现浮点数的精确计算

    在Java编程中,使用`float`和`double`类型进行浮点数计算时经常会遇到精度丢失的问题。这是因为浮点数在计算机内部是以二进制形式存储的,而某些十进制小数无法用二进制精确表示,从而导致计算结果出现误差。例如,`...

    java_double_精度

    Java 双精度浮点数精度问题解决方案 Java 中的双精度浮点数(double)类型在进行运算时经常出现精度丢失的问题,这是由于双精度浮点数在计算机内部的存储方式所致。双精度浮点数使用 64 位二进制数来存储小数,然而...

    Java Double 精度问题总结

    虽然 `double` 提供了相对较高的精度,但在涉及精确数学运算(特别是涉及到小数值)时,由于其内部采用二进制浮点数格式存储,仍会出现精度丢失的情况。这种精度丢失的现象对于需要高精度计算的应用来说是一个常见的...

    解决java数值范围以及float与double精度丢失的问题

    下面我们将详细探讨Java中的数值范围、float和double类型的精度问题,并且提供解决方案。 一、Java中的数值范围 Java中的基本数据类型有多种,包括整数类型(int、long)、浮点数类型(float、double)。每种类型...

    解决JavaScript数字精度丢失问题的方法

    解决方案(一个对象+一个函数) 一、JS数字精度丢失的一些典型问题 1. 两个简单的浮点数相加 0.1 + 0.2 != 0.3 // true 这真不是 Firebug 的问题,可以用alert试试 (哈哈开玩笑)。 看看Java的运算结果 再看看...

    java练习题4.txt

    通过这个Java练习题,学习者不仅可以练习基本的算术运算和程序结构,还可以学习到如何将现实世界的问题转换成编程问题,并用代码实现解决方案。此外,还能够加深对Java语法、变量定义、方法调用等编程基础的理解。

    java考试复习资料

    - **解决方案**:使用`BigDecimal`类来进行精确的浮点数运算。 #### 十六、递增运算符的差异 - `++i`:先进行自增运算,再返回结果。 - `i++`:先返回当前值,再进行自增运算。 #### 十七、程序结构 程序结构...

    挣钱兑零(Java)

    这种简单问题的解决方案通常不需要复杂的类设计或对象实例化。 这个程序对于初学者来说,是一个很好的实践案例,它展示了基本的输入/输出处理、数据类型转换、数学运算以及控制流。通过这个程序,学习者可以理解...

    【项目实践】商业计算怎样才能保证精度不丢失(csdn)————程序.pdf

    2. **定长整数**:另一种解决方案是使用定长整数类型,如Java中的`BigInteger`,尽管它不处理小数,但在处理大整数时可以保持精度。在商业计算中,如果金额不涉及小数部分,这种方法也可以考虑。 在处理BigDecimal...

    【SpringBoot】jackson序列化解决超大整数浏览器精度损失问题 demo

    JavaScript使用IEEE 754标准来存储浮点数,Number类型可以精确表示的最大整数是2^53 - 1(即9007199254740992),超过这个范围的整数可能会丢失精度。例如,当你尝试在JavaScript中显示9007199254740993,实际上会...

    POJ1001-Precision power

    2. **浮点数计算**:在计算机中,浮点数是以二进制形式存储的,这导致了某些十进制小数不能精确表示,因此在进行浮点数运算时可能会出现精度丢失。例如,1.0/3.0的二进制表示是无限循环的,计算机只能存储有限位,...

    长整数与浮点互转

    在计算机科学中,数据类型是表示各种基本数据的类,其中长整数(Long Integer)和浮点数(Floating-point)是两种常见的数值类型。...而“长转浮.exe”这样的实用工具,则是这一领域中方便快捷的解决方案。

    JAVA入门经典案例.pdf

    1. 变量使用常用错误及解决方案 - **未经声明的变量**:在Java中,变量使用前必须声明其类型和名称。例如,`a = 1;` 会导致编译错误,因为变量a未声明。正确做法是先声明变量,如 `int a;` 再进行赋值。 - **不...

    JAVA编程指南.pdf

    陷阱的分析通常包括三个主要步骤:症状或问题的识别、问题的根源分析以及解决方案的提出。在遇到问题时,首要任务是确定问题出在哪里,即哪个代码段导致了问题;接着深入到问题的核心,探究其底层原因,可能是由于不...

    java 解惑.pdf

    以上仅列举了部分谜题,每个谜题都深入探讨了Java编程中的陷阱和缺陷,并提供了详尽的解决方案。通过学习这些谜题,不仅可以增加对Java语言的理解,还能帮助程序员避免常见的错误,提高代码质量。

    java解惑

    - **精度丢失问题:**由于`1.10`的近似表示与真实值存在微小差异,在进行算术运算时累积误差。 ##### 解决方案 为了避免此类问题,可以采取以下几种策略: 1. **使用整数类型:**如使用`int`或`long`,以分为单位...

    java面试笔记整理,包含java,redis,kafka等

    - **精度问题:** 浮点数在表示小数值时可能会存在精度丢失,不适合用于财务计算。 - **舍入误差:** 浮点运算可能产生无法精确表示的结果,导致不准确的计算结果。 #### 十二、值传递与引用传递 - **值传递:** 传递...

    Java经典面试题+答案(带书签)pdf

    - 解决方案包括排除冲突依赖项、使用特定版本的依赖项等。 **20. 基本数据类型强制转换** - 强制类型转换可以将一种数据类型转换为另一种。 - 如将`double`转换为`int`时,会丢失小数部分。 **21. 创建对象时,...

Global site tag (gtag.js) - Google Analytics