Java中2减1.1等于几?

在Java中有一个奇怪的现象,我们编写代码2-1.1,原本以为结果是非常明显的0.9,但答案却让人大吃一惊,如图:

原因在于:Java基本数据类型中的float、double类型的实质是浮点数,浮点数不能存储精确的数据,这样的话,浮点数在进行计算的时候,计算结果就不是精确的值。所以这里得出经验,在实际开发中,我们在对数值进行计算的时候,应尽量避免使用Java的+ - * / 等运算符,因为容易出现损失精度的问题,导致最终的计算结果错误。

尤其是在电商平台中都是杜绝使用此种计算方式的,因为由于这种计算导致金额出现的误差,所带来的损失是无法估量的,也许就因为差一分钱,导致报表计算错误,客户账单对不上,都会带来大麻烦。所以我们有必要找到一种正确的计算方法。

Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。

1、加法

2、减法

3、乘法

在上述的截图中,会发现我们在做运算之前,都会将double值转化为String值,尽管BigDecimal提供了多种构造方法,也是支持传入double值的,但这里我们并不推荐。因为传入double值是容易出问题的,如图:

a)参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入

newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

b)另一方面,String 构造方法是完全可预知的:写入 newBigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法。

c)当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法。将double转换为String,也可以使用String的static方法:String.valueOf(double)。

4、除法

在使用除法时,我们发现divide方法中,我们多传入了几个参数。如果对于可以除尽的数不传入这两个参数也是没有问题的,但如果我们使用100除以3会出现什么问题呢?

我们发现报错了,原因在于:通过BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result. 所以不管能不能除尽,我们都要防患于未然告诉运算器我们除不尽的方案是什么。

BigDecimal已经帮助我们定义好了舍入模式,只有在作除法运算或四舍五入时才用到舍入模式。如下图:

这么多的四舍五入模式,我们在实际开发中应该使用那种呢,这个还是要分情况的。我倒是建议使用UNNECESSARY这种模式:计算结果是精确的,不需要四舍五入,那你可能会说这样不就有问题了吗?别着急,待计算完成后我们再单独对结果进行四舍五入?为什么要这样呢?因为我们不能保证我们的程序中只存在一次计算,如果我们有一个公式要连续对数值进行乘法和除法,每次都四舍五入,那计算结果才会有问题,但如果我们只对最终的结果值四舍五入就没有问题了,因为多数在保存的时候,数据库都要求保留两位小数。首先我们来看下不同的模式下计算的结果值有什么差异?

在UNNECESSARY的时候最为精确。因为其保留的小数也最多。具体我们可以打开源代码自己看下原因。那最终我们如何将数值保留两位小数呢?

例如:

猜你喜欢

转载自blog.csdn.net/java03_15/article/details/85161747
今日推荐