大数据培训
美国上市大数据培训机构

400-111-8989

热门课程

使用BigDecimal实现精确加减乘除运算

  • 发布:大数据培训
  • 来源:大数据教程
  • 时间:2018-03-22 11:03

商业计算不要使用浮点数

在前几期的每日一练题目中,有一道题目是,需要精确计算的时候一定要使用BigDecimal。在本科时候其实计算机原理就曾经学过计算机的浮点数表示,但是从小数学的惯性思维上,总觉得乘法就移一下小数点,不会出问题。在商业计算中遇到带小数点的“元”转换为“分”的时候,进行*100的操作总觉得double根本不会出问题,于是怒踩了一坑。

简单理解为什么会有精度问题

大家都知道计算机要用二进制表示,基本的十进制和二进制的换算应该都清楚。例如:

0.5(十进制) = 0.1(二进制),因为2^-1是0.5。

0.25(十进制) = 0.01(二进制),因为2^-2是0.25。

那0.2呢,怎么表示呢,表示不出来啊。那就只能找个最接近的近似值来代表。

所以0.2的二进制小数是0.0011001100110011.......,也就是(2^-3)+(2^-4)+(2^-7)+(2^-8)+.....

简单介绍IEEE754表示法

以Java中的double值0.2为例,double大小为32位。

System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(0.2)));

运行以上代码可以看到double类型0.2在机器中的二进制表示为:11111111001001100110011001100110011001100110011001100110011010。

需要将其补齐64位,在前面加两个0:

0011111111001001100110011001100110011001100110011001100110011010。

按照IEEE754表示法,我们将其分为三段:

符号(64位):0,

阶码(63-53位):01111111100,

尾数(51-1位):001100110011001100110011001100110011001100110011010。

System.out.println(Integer.valueOf("01111111100",2));

运行以上代码可以看到阶码的十进制值为1020。当阶码不为0或2047时,需要减去1023这个偏移量,并且尾数前面隐藏了”1.”。因此,调整后的表示为:

符号:0,

阶码:-3(十进制),

尾数:1.1001100110011001100110011001100110011001100110011010。

最终,按照-1^符号 尾数 2^阶码的计算方式,0.2真正的二进制值如下所示,和真正的0.2明显是有偏差的:

0.0011001100110011001100110011001100110011001100110011010

Java中正确使用BigDecimal

在Java中遇到商业计算,可以方便的使用BigDecimal来解决精度问题。但是使用中也存在需要注意的地方。

double d = 0.2; System.out.println(new BigDecimal(d));

运行以上代码可以看到,java中表示的0.2的值为:

0.200000000000000011102230246251565404236316680908203125,是有偏差的。

但是虽然用了BigDecimal,为什么数据还是有问题?这是因为在使用BigDecimal时,不要使用double参数的构造方法,而是要使用String参数的构造方法,或是静态方法valueOf,才能够保证数据的准确性。

//两种正确的使用方式

System.out.println(new BigDecimal("0.2"));

System.out.println(BigDecimal.valueOf(0.2));

BigDecimal类创建的是对象,不能使用传统的+、-、*、/等算术运算符直接对其进行数学运算,而必须调用其对应的方法.方法的参数也必须是BigDecimal类型的对象.

构造BigDecimal 对象常用方法

方法一

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 的首选方法。

感谢大家阅读由大数据教程分享的“使用BigDecimal实现精确加减乘除运算”希望对大家有所帮助,更多精彩内容请关注大数据培训机构官网

免责声明:本文由小编转载自网络,旨在分享提供阅读,版权归原作者所有,如有侵权请联系我们进行删除

预约申请免费试听课

上一篇:大数据分析不能不懂的6个核心技术
下一篇:Java多线程实现的三种方式!

大数据分析及其在常模研发中的应用

你真的理解了MVC, MVP, MVVM吗?

Spring中定时器实现

Servlet请求和响应

选择城市和中心
贵州省

广西省

海南省