我在做一个算法时,发现java中出现了一个奇怪的误差,数值均以double型处理
1/3.0=0.33333333333333333333(16个)
2/3.0=0.66666666666666666666(16个)
这是正确的
可是~~~~~
8/3.0=2.66666666666666666665 这是为什么呢?
64/3.0=21.3333333333333333332 这又是为什么呢?
原先我以为是假分数造成的,可是~~~~~~~~
32/3.0=10.6666666666666666666 正确这下好,有没有人能够解释一下,这是为什么呢?我想应该和内部机制有关,请教高人给个解释
1/3.0=0.33333333333333333333(16个)
2/3.0=0.66666666666666666666(16个)
这是正确的
可是~~~~~
8/3.0=2.66666666666666666665 这是为什么呢?
64/3.0=21.3333333333333333332 这又是为什么呢?
原先我以为是假分数造成的,可是~~~~~~~~
32/3.0=10.6666666666666666666 正确这下好,有没有人能够解释一下,这是为什么呢?我想应该和内部机制有关,请教高人给个解释
System.out.println(new BigDecimal(1 / 3.0));
System.out.println(new BigDecimal(64 / 3.0));看看这个输出结果研究吧
要自己写程序解决float 的精度问题
项目按说都结项了, 但最近出了不大不小的麻烦, 就是因为程序中对金额税率的计算使用了float型的数据,造成结果精度不够,所以数据有损失。 多张报表的结果核对不上。
上网查了一些相关的资料,发现这是因为float的精度只有7位(小数点后7位)。 比如在保存1.05(日本的现行税率)这个数时,float型的变量实际存储的是1.04999998... (由于1.05在用2进制保存时,和我们看到的10进制的表示不同,它的2进制表示是小数点后无穷尽的,学过《计算机组成原理》的同学都知道) 。 正是因为这样,在和一个较大的数(上百万,在日本的这个数额稀松平常)的相乘以后,误差就被放大了。
然后继续查了一些解决方法,double型的数据精度比float要高,但也就只有11位,也就是说,能对付上百亿。 对于我们目前的系统来说,应该是够用了,日常单比业务不会超过千万,月季的时候,也不会到10亿。过亿的数据也都是整形基础上合计的。
对于精度要求更高的程序,Java 提供一个BigDecimal 类,
但要注意,该类不是一个基本类型,而是一个封装的类。 所以在使用中非常不便的是,它的运算都是通过函数来完成,而不是通过+-*/ 之类的运算符来完成。
所以,这里告诫大家, 在做财务相关的软件时,一定要慎重选择小数的类型或类。
private static final int DEF_DIV_SCALE = 10;
改为
private static final int DEF_DIV_SCALE = 16;
的时候得到的结果依然是 2.6666666666666665看来内部的机制果然是铁的定律,无法抗拒啊??~~!!
我已经有些疑惑了,是不是只要开始规定了double的数字之后,当2.6666666666666666出现,程序就会认为是2.6666666666666665
至少我在使用了BigDecimal之后,认为是这样因为我设定
double ft = 2.6666666666666666;
double et = 8.0/3;
BigDecimal fd = new BigDecimal(ft);
BigDecimal ed = new BigDecimal(et);
System.out.println(fd);
System.out.println(ed);
显示出来的结果是一样的
2.666666666666666518636930049979127943515777587890625
而且
System.out.println(ft);
System.out.println(et);
显示出来的结果是一样的
2.6666666666666665
非常感谢你们的回答,不过真理似乎还离我们有一定的距离啊
double ft = 2.6666666666666666;
double et = 8.0/3;
BigDecimal fd = new BigDecimal(ft); //不要这样。改为:BigDecimal fd = new BigDecimal("2.666666666666666666");
BigDecimal ed = new BigDecimal(et);//不要这样,改为: BigDecimal ed = new BigDecimal("8.0").divide(new BigDecimal("3"),MathContext.DECIMAL128);
System.out.println("fd="+fd);
System.out.println("ed="+ed);
结果将是:
fd=2.666666666666666666
ed=2.666666666666666666666666666666667