我是靠谱客的博主 专注发卡,这篇文章主要介绍java求小数高精度运算,现在分享给大家,希望可以做个参考。

java求小数高精度

在实际编码中,会遇到很多高精度的事例,比如,在计算金钱的时候就需要保留高精度小数,这样计算才不会有太大误差

有以下实现可以得证:当两个float型的数字相加,得到的结果和我们的预期结果是有误差的

复制代码
1
2
3
4
5
6
7
8
float x = 2.01f; float y = 124.01f; System.out.println(x + y); //预期输出:126.02 实际输入:126.020004 System.out.println(x); System.out.println(y); //预期输出:2.01 124.02 实际输入:2.01 124.02

那为什么我们在直接给float赋值在输出时没有看到精度损失而在运算时却会出现呢?

好像是因为编译器会进行优化,当我们存储的数据特别接近的时候,编译器会很贴心的返回我们想看到的数值(即二进制浮点数并不能准确的表示0.1这个十进制小数,它使用了0.100000001490116119384765625来代替0.1。),至于到了运算中,就会出现精度损失较大从而看到了真相。(查阅资料得知)

解决方法

BigDecimal 原理

java开发中一般使用BigDecimal 来避免出现精度丢失问题,简单来说就是BigDecimal 通过借助整数来表示小数的方式,因为对于整数而言,二进制和十进制是完全一一对应的,用整数来表示小数,再记录下小数的位数,就可以完美的解决该问题。

BigDecimal 用法

java.math.BinInteger 类和 java.math.BigDecimal 类都是Java提供的用于高精度计算的类.其中 BigInteger 类是针对大整数的处理类,而 BigDecimal 类则是针对大小数的处理类.

BigDecimal构造方法

复制代码
1
2
3
4
BigDecimal BigDecimal(double d); //不允许使用 BigDecimal BigDecimal(String s); //常用,推荐使用 static BigDecimal valueOf(double d); //常用,推荐使用
  1. double 参数的构造方法,不允许使用! 因为它不能精确的得到相应的值;
  2. String 构造方法是完全可预知的: 写入 new BigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的0.1; 因此,通常建议优先使用 String 构造方法;
  3. 静态方法 valueOf(double val) 内部实现,仍是将 double 类型转为 String 类型; 这通常是将 double(或float)转化为 BigDecimal 的首选方法;

演示

复制代码
1
2
3
4
5
6
7
System.out.println(new BigDecimal(0.2)); System.out.println(BigDecimal.valueOf(0.2)); //输出 0.200000000000000011102230246251565404236316680908203125 0.2

BigDecimal常用操作

我们通过一个工具类源码来体会BigDecimal的常规用法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package com.util; import java.math.BigDecimal; /** * 提供精确的浮点数运算(包括加、减、乘、除、四舍五入)工具类 */ public class ArithUtil { // 除法运算默认精度 private static final int DEF_DIV_SCALE = 10; private ArithUtil() { } /** * 精确加法 */ public static double add(double value1, double value2) { BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.add(b2).doubleValue(); } /** * 精确减法 */ public static double sub(double value1, double value2) { BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.subtract(b2).doubleValue(); } /** * 精确乘法 */ public static double mul(double value1, double value2) { BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); return b1.multiply(b2).doubleValue(); } /** * 精确除法 使用默认精度 */ public static double div(double value1, double value2) throws IllegalAccessException { return div(value1, value2, DEF_DIV_SCALE); } /** * 精确除法 * @param scale 精度 */ public static double div(double value1, double value2, int scale) throws IllegalAccessException { if(scale < 0) { throw new IllegalAccessException("精确度不能小于0"); } BigDecimal b1 = BigDecimal.valueOf(value1); BigDecimal b2 = BigDecimal.valueOf(value2); // return b1.divide(b2, scale).doubleValue(); return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 四舍五入 * @param scale 小数点后保留几位 */ public static double round(double v, int scale) throws IllegalAccessException { return div(v, 1, scale); } /** * 比较大小 */ public static boolean equalTo(BigDecimal b1, BigDecimal b2) { if(b1 == null || b2 == null) { return false; } return 0 == b1.compareTo(b2); } }

最后

以上就是专注发卡最近收集整理的关于java求小数高精度运算的全部内容,更多相关java求小数高精度运算内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(92)

评论列表共有 0 条评论

立即
投稿
返回
顶部