BidDecimal对于精确性的问题,以及如何保持输入数据的准确性

BidDecimal对于精确性的问题,以及如何保持输入数据的准确性

  • 引子
  • 题目要求
  • 开始编写时候的错误
  • 改进
  • 分析
  • 结论

引子

对于这个问题,我们先引入一个案例,如下:

题目要求

有以下double数组:
double[] arr = {0.1, 0.2, 0.33, 4.4, 5.55, 0.006};
请编程计算它们的总值及平均值(四舍五入保留小数点后2位)

开始编写时候的错误

没有对数组中的数据进行字符串的转化,导致了计算结果的不精确,如下:

        double[] arr = {0.1, 0.2, 0.33, 4.4, 5.55, 0.006};
        BigDecimal total = new BigDecimal(0);
        for (int i = 0; i < arr.length; i++) {
            BigDecimal bd = new BigDecimal(arr[i]);
            total = total.add(bd);
        }
        System.out.println("数组中的各个元素和为:" + total);

        BigDecimal average = total.divide(BigDecimal.valueOf(arr.length), 2, BigDecimal.ROUND_HALF_UP);
        System.out.println("它们的平均数为:" + average);
//输出结果
数组中的各个元素和为:10.58600000000000020995705174442491625086404383182525634765625
它们的平均数为:1.76

改进

后来经过改进,对bd的格式进行了限定

double[] arr = {0.1, 0.2, 0.33, 4.4, 5.55, 0.006};
        BigDecimal total = new BigDecimal("0");
        for (int i = 0; i < arr.length; i++) {
            BigDecimal bd = new BigDecimal(String.valueOf(arr[i]));
            total = total.add(bd);
        }
        System.out.println("数组中的各个元素和为:" + total);

        BigDecimal average = total.divide(BigDecimal.valueOf(arr.length),2,BigDecimal.ROUND_HALF_UP);
        System.out.println("它们的平均数为:"+average);
//输出结果
数组中的各个元素和为:10.586
它们的平均数为:1.76

分析

        BigDecimal bd1 = new BigDecimal(Double.valueOf(0.1));
        System.out.println("bd1是" + bd1);
        BigDecimal bd2 = new BigDecimal(0.1f);
        System.out.println("bd2是" + bd2);
        BigDecimal bd3 = new BigDecimal(0.1);
        System.out.println("bd3是" + bd3);
        BigDecimal bd4 = new BigDecimal("0.1");
        System.out.println("bd4是" + bd4);
        System.out.println("0.1是" + 0.1);
        System.out.println("Float.valueOf(0.1f)" + Float.valueOf(0.1f));
//输出结果
bd1是0.1000000000000000055511151231257827021181583404541015625
bd2是0.100000001490116119384765625
bd3是0.1000000000000000055511151231257827021181583404541015625
bd4是0.1
0.10.1
Float.valueOf(0.1f)0.1

从这里大家应该已经能看出来了,所谓的更精确的BigDecimal其实与我们理解意义上的精确是不一样的,有人会问了,既然后三个(BigDecimal(“0.1”);0.1;0.1f)结果都是我们常识中认为的0.1,那我们直接用0.1不就好了,干嘛非要用BigDecimal呢?
在讲0.1究竟是什么东西之前,我先再给大家写一段小玩意儿:

		System.out.println(0.1);
        System.out.println(0.2);
        System.out.println(0.1 + 0.2);
        System.out.println(0.3);
        double a = 0.1;
        double b = 0.2;
        System.out.println(a + b);
//输出结果
0.1
0.2
0.30000000000000004
0.3
0.30000000000000004

其实,0.1作为我们熟知的一个小数,它无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数).这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值).那为什么我们sout的语句输出的0.1(会默认输入的为Double)依旧直接打印为0.1,而不是像上面三个,带了一串尾巴呢?我为大家追踪一下sout的源码

        System.out.println(0.1);
        public void println(double x) {
        synchronized(this) {
            this.print(x);
            this.newLine();
        }
    }
        public void print(double d) {
        this.write(String.valueOf(d));
    }

明白了吧,你打印的,只是0.1这么个被转成字符串的东西,而不是计算机中所认为的0.1Double,也就是上面所说的那句话,0.1无法准确地表示为 double.

有人又会提出质疑了,那这个也不能用,你提的BigDecimal精确倒是精确,那也是一串尾巴,那我用啥?
大家别忘了我上面写过的bd4啊,我再把上面那段代码拿下来:

        BigDecimal bd1 = new BigDecimal(Double.valueOf(0.1));
        System.out.println("bd1是" + bd1);
        BigDecimal bd2 = new BigDecimal(0.1f);
        System.out.println("bd2是" + bd2);
        BigDecimal bd3 = new BigDecimal(0.1);
        System.out.println("bd3是" + bd3);
        BigDecimal bd4 = new BigDecimal("0.1");
        System.out.println("bd4是" + bd4);
        System.out.println("0.1是" + 0.1);
        System.out.println("Float.valueOf(0.1f)" + Float.valueOf(0.1f));
//输出结果
bd1是0.1000000000000000055511151231257827021181583404541015625
bd2是0.100000001490116119384765625
bd3是0.1000000000000000055511151231257827021181583404541015625
bd4是0.1
0.10.1
Float.valueOf(0.1f)0.1

是不是?bd4的输出结果是不是也是0.1?什么?你说它是字符串?那你接着看

//输出结果
        BigDecimal bd1 = new BigDecimal(0.1);
        BigDecimal bd2 = new BigDecimal(0.2);
        BigDecimal bd3 = new BigDecimal("0.1");
        BigDecimal bd4 = new BigDecimal("0.2");
        BigDecimal sum1 = bd1.add(bd2);
        BigDecimal sum2 = bd3.add(bd4);
        System.out.println("bd1是" + bd1);
        System.out.println("bd2是" + bd2);
        System.out.println("bd3是" + bd3);
        System.out.println("bd4是" + bd4);
        System.out.println("sum1是" + sum1);
        System.out.println("sum2是" + sum2);
//输出结果
bd1是0.1000000000000000055511151231257827021181583404541015625
bd2是0.200000000000000011102230246251565404236316680908203125
bd3是0.1
bd4是0.2
sum1是0.3000000000000000166533453693773481063544750213623046875
sum2是0.3

神奇吧?也就是说,所有在BigDecimal中的运算,你尽管加上双引号,那样的结果就是我们所熟知的结果.无论在输入 计算 还是打印的过程中,都会展现给我们0.1 + 0.2 = 0.3(依旧提醒大家不要字符串拼接±*/,否则你懂得)

结论

数学运算,调用BigDecimal中的运算方法,数字加上双引号,变成字符串即可

你可能感兴趣的:(BigDecimal,数组)