首页 > 编程知识 正文

面试题(bigdecimal比较是否相等)

时间:2023-05-06 16:56:52 阅读:99391 作者:3208

高质量的物品,及时送达

链接| HikariCP

来源| www.jianshu.com/p/c81edc59546c

# 前言

我们都知道浮点变量在计算时会失去精度。以下代码:

system . out . println(0.050.01);system . out . println(1.0-0.42);system . out . println(4.015 * 100);system . out . println(123.3/100);产量:0.060000000000000000050 . 5800000000005 . 5800000005 . 580005 . 5800005 . 580005 . 580005可以看出,在Java中操作浮点数时,精度会有所损失。那么如果我们计算商品的价格,就会出现问题。很有可能我们手里有0.06元,却买不到一个0.05元和一个0.01元的商品。

小贴士:可以在微信上搜索:Java后端,关注后加入我们自己的交流群。

因为如上图,它们的总和是0.060000005。这无疑是一个非常严重的问题,尤其是当电商网站的并发量上去之后,问题将是巨大的。这可能导致无法下订单或对账问题。所以接下来,我们可以用Java中的BigDecimal类来解决这类问题。

普及一下:

Java中float的精度是6-7个有效数字。双精度是15-16位。

00-1010施工员:

构造函数描述BigDecimal(int)用参数指定的整数值创建一个对象。BigDecimal(double)用参数指定的双精度值创建一个对象。大十进制(长)用参数指定的长整数值创建一个对象。BigDecimal(字符串)创建一个对象,其数值由参数指定为字符串。功能:

方法描述在add(BigDecimal) BigDecimal对象中添加值,然后返回该对象。减法(BigDecimal) BigDecimal)减去BigDecimal对象中的值,然后返回该对象。乘法(大十进制)将大十进制对象中的值相乘,然后返回该对象。将BigDecimal对象中的值除(BigDecimal),然后返回该对象。ToString将BigDecimal对象的数值转换为字符串。DoubleValue以双精度形式返回BigDecimal对象中的值。FloatValue以单精度形式返回BigDecimal对象中的值。LongValue以长整数的形式返回BigDecimal对象中的值。IntValue以整数形式返回BigDecimal对象中的值。由于通用的数字类型,如双精度,超过16位的数字无法准确表示。

00-1010当我们使用BigDecimal时,使用它的BigDecimal(String)构造函数来创建对象是有意义的。其他的,比如BigDecimal b=new BigDecimal(1),仍然存在丢失精度的问题。以下代码:

BigDecimal a=新的big decimal(1.01);BigDecimal b=新的BigDecimal(1.02);BigDecimal c=新的big decimal(' 1.01 ');BigDecimal d=新的big decimal(' 1.02 ');system . out . println(a . add(b));system . out . println(c . add(d));输出:2.030000000000000002664535259100375697016716003417968752.03可见损耗精度BigDecimal更极端。但是,在使用Bigdecimal的BigDecimal(String)构造函数操作变量时,就没有这样的问题。原因全在计算机组成原理,它们的编码决定了这个结果。Long可以准确存储19位数字,double只能准备存储16位数字。

Double可以存储16位以上,因为它有exp位,但需要以低阶不精确为代价。如果需要准确存储19位以上,必须使用BigInteger保存,当然要牺牲一些性能。因此,当我们一般使用BigDecimal来解决业务操作中精度丢失的问题时,在声明BigDecimal对象时,必须使用它来构造一个参数为String的类型的构造函数。

同时,这个原理在Effective Java和MySQL中也有提及。浮点和双精度只能用于科学计算和工程计算。我们需要在商业运作中使用BigDecimal。

此外,我们还从源代码注释中给出了官方解释。以下是对BigDecimal类的双类型参数的构造函数的部分注释:

*此构造函数的结果

can be somewhat unpredictable.* One might assume that writing {@code new BigDecimal(0.1)} in* Java creates a {@code BigDecimal} which is exactly equal to* 0.1 (an unscaled value of 1, with a scale of 1), but it is* actually equal to* 0.1000000000000000055511151231257827021181583404541015625.* This is because 0.1 cannot be represented exactly as a* {@code double} (or, for that matter, as a binary fraction of* any finite length). Thus, the value that is being passed* <i>in</i> to the constructor is not exactly equal to 0.1,* appearances notwithstanding.……* When a {@code double} must be used as a source for a* {@code BigDecimal}, note that this constructor provides an* exact conversion; it does not give the same result as* converting the {@code double} to a {@code String} using the* {@link Double#toString(double)} method and then using the* {@link #BigDecimal(String)} constructor. To get that result,* use the {@code static} {@link #valueOf(double)} method.* </ol>public BigDecimal(double val) {this(val,MathContext.UNLIMITED);}

第一段也说的很清楚它只能计算的无限接近这个数,但是无法精确到这个数。第二段则说,如果要想准确计算这个值,那么需要把double类型的参数转化为String类型的。并且使用BigDecimal(String)这个构造方法进行构造。去获取结果。

# 正确运用BigDecimal

另外,BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象,由刚才我们所罗列的API也可看出。

在一般开发过程中,我们数据库中存储的数据都是float和double类型的。在进行拿来拿去运算的时候还需要不断的转化,这样十分的不方便。这里我写了一个工具类:

/*** @author: Ji YongGuang.* @date: 19:50 2017/12/14.*/public class BigDecimalUtil {private BigDecimalUtil {}public static BigDecimal add(double v1, double v2) {// v1 + v2BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.add(b2);}public static BigDecimal sub(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.subtract(b2);}public static BigDecimal mul(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.multiply(b2);}public static BigDecimal div(double v1, double v2) {BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));// 2 = 保留小数点后两位 ROUND_HALF_UP = 四舍五入return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);// 应对除不尽的情况}}

该工具类提供了double类型的基本的加减乘除运算。直接调用即可

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。