zoukankan      html  css  js  c++  java
  • BigDecimal类学习笔记

    float类型和double类型精度失真

    float类型和double类型在高精度场景下会出现精度失真的情况。

    例如:

    System.out.println(0.99999999f);  // 八个9

    输出:

    1.0

    这就涉及浮点数在计算机中的表示方式。

    浮点数的表示方式:

    S:符号位(01负)

    M尾数(小数点后面的数)

    E阶码(指数)

     

    阶码(指数):

      float类型:8位,表示范围为-127 ~ 128

      double类型:11位,表示范围为-1023 ~ 1024

    尾数部分:

      float类型:23位,十进制2^23=8388608,所以十进制精度只有6 ~ 7位;

      double类型:52位,十进制就是 2^52 = 4503599627370496,所以十进制精度只有15 ~ 16位。

    浮点数二进制表示实例:(转换工具:http://binaryconvert.com/convert_float.html

    -0.5转化为二进制数为:-0.1

    S=1, M=0, E=-1

    进行二进制浮点数表示时,E需加127(即为126)(二进制:01111110

    所以-0.5f二进制浮点数表示为:

    10111111 00000000 00000000 00000000

    来看1.0f0.9999999f的浮点数二进制表示:

    1.0转化为二进制数为:1.0

    S=0, M=0, E=0

    进行二进制浮点数表示时,E需加127(二进制:01111111

    所以1.0f二进制浮点数表示为:

    00111111 10000000 00000000 00000000

    同理,0.99999999f二进制浮点数表示为:

    00111111 10000000 00000000 00000000

    显然,在计算机中1.0f0.999999999f的浮点数表示是一致的。

    在金融领域这样的精度失真将是致命的。Java提供了BigDecimal类实现高精度计算。

    BigDecimal

      BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂。因此,BigDecimal表示的数值是(unscaledValue×10-scale)。BigDecimal对象表示的是不可变的,任意精度的有符号十进制数

    构造器

    例:

    BigDecimal num = new BigDecimal(0.1);   // 利用double型构造
    System.out.println(num);
    // 0.1000000000000000055511151231257827021181583404541015625
    
    BigDecimal num = new BigDecimal("0.1"); // 利用String构造
    System.out.println(num);                // 0.1
    
    // 利用数值型进行构造会产生不可预见性,通常使用字符串构造。
    
    char[] arr = {'1','2','3','4','5','6'};
    BigDecimal num = new BigDecimal(arr,1,4); // 使用指定字符数组,指定索引及长度构造
    System.out.println(num);  // 2345

    BigDecimal中的RoundingMode

    舍入规则

    例:

         BigDecimal positive_num = new BigDecimal("0.145");
            BigDecimal negative_num = new BigDecimal("-0.145");
            System.out.println(positive_num.setScale(2,RoundingMode.CEILING));  // 0.15 向正无穷大的方向舍入(Math.round即为此模式)
            System.out.println(negative_num.setScale(2,RoundingMode.CEILING));  // -0.14 向正无穷大的方向舍入
    
            System.out.println(positive_num.setScale(2,RoundingMode.FLOOR));    // 0.14 向负无穷大的方向舍入
            System.out.println(negative_num.setScale(2,RoundingMode.FLOOR));    // -0.15 向负无穷大的方向舍入
    
            System.out.println(positive_num.setScale(2,RoundingMode.UP));       // 0.15 向远离零的方向舍入
            System.out.println(negative_num.setScale(2,RoundingMode.UP));       // -0.15 向远离零的方向舍入
    
            System.out.println(positive_num.setScale(2,RoundingMode.DOWN));     // 0.14 向接近零的方向舍入
            System.out.println(negative_num.setScale(2,RoundingMode.DOWN));     // -0.14 向接近零的方向舍入
    
            System.out.println(positive_num.setScale(2,RoundingMode.HALF_UP));  // 0.15 四舍五入模式
            System.out.println(negative_num.setScale(2,RoundingMode.HALF_UP));  // -0.15 四舍五入模式
    
            System.out.println(positive_num.setScale(2,RoundingMode.HALF_DOWN));// 0.14 五舍六入模式
            System.out.println(negative_num.setScale(2,RoundingMode.HALF_DOWN));// -0.14 五舍六入模式
            
    
            /**
             * 银行家舍入(Banker's Round),金融领域尽量使用此舍入模式
             *  舍去位小于5,直接舍去;
             *  舍去位大于等于6,进位后舍去;
             *  舍去位等于5时:
             *          5后有非0数字,进位后舍去
             *          5后面是0,则5的前一位是奇数进位,偶数舍去
             */
            BigDecimal num1 = new BigDecimal("0.254");  // 舍去位小于5
            System.out.println(num1.setScale(2,RoundingMode.HALF_EVEN)); // 0.25
    
            BigDecimal num2 = new BigDecimal("0.256");  // 舍去位大于等于6
            System.out.println(num2.setScale(2,RoundingMode.HALF_EVEN)); // 0.26
    
            BigDecimal num3 = new BigDecimal("0.2551");  // 舍去位等于5,5后面非0
            System.out.println(num3.setScale(2,RoundingMode.HALF_EVEN)); // 0.26
    
            BigDecimal num4 = new BigDecimal("0.255");  // 舍去位等于5,5后面是0,5的前一位是奇数进位
            System.out.println(num4.setScale(2,RoundingMode.HALF_EVEN)); // 0.26

    BigDecimal常用方法的使用

    例:

            BigDecimal num1 = new BigDecimal("125");
            BigDecimal num2 = new BigDecimal("4");
            System.out.println(num1.add(num2));    // 加法
            System.out.println(num1.divide(num2)); // 除法
            System.out.println(num1.divide(num2, RoundingMode.CEILING)); // 指定舍入规则的除法
            System.out.println(num1.divide(num2, 1,RoundingMode.CEILING)); // 指定小数位数和舍入规则的除法
            System.out.println(num1.divideToIntegralValue(num2)); // 除法只保留整数部分
            System.out.println(num1.remainder(num2));  // 除法只保留余数
            BigDecimal[] result = num1.divideAndRemainder(num2); // 带余数除法
            for (BigDecimal bigDecimal : result) {
                System.out.println(bigDecimal.toString());
            }
            System.out.println(num1.pow(2));  // 次方
            System.out.println(num1.subtract(num2)); // 减法
            System.out.println(num1.multiply(num2)); // 乘法
    
            BigDecimal num3 = new BigDecimal("-2");
            System.out.println(num3.abs());   // 绝对值
    
            System.out.println(num1.compareTo(num2)); // num1>num2返回1;num1>num2返回-1;num1==num2返回0
    
            byte i = num1.byteValueExact();  // 转化为byte类型,-128<=num1<=127,否则抛异常
            System.out.println(i);
    
            System.out.println(num1.byteValue()); // 转化为byte类型,越界值出错,不抛异常
    
            int int_value = num1.intValue();   // 转化为int类型
            System.out.println(int_value);
    
            float float_value = num1.floatValue(); // 转化为float类型
            System.out.println(float_value);
    
            double double_value = num1.doubleValue(); // 转化为double类型
            System.out.println(double_value);
    
            long long_value = num1.longValue();  // 转化为long类型
            System.out.println(long_value);
    
            System.out.println(num1.max(num2));  // 返回两者最大值
    
            System.out.println(num1.min(num2)); // 返回两者最小值
    
            BigDecimal num4 = new BigDecimal("12.345");
            System.out.println(num4.movePointLeft(1)); // 1.2345 小数点左移1位
            System.out.println(num4.movePointLeft(-1)); // 123.45 小数点右移1位
    
            System.out.println(num4.movePointRight(1)); // 123.45 小数点右移1位
            System.out.println(num4.movePointRight(-1)); // 1.2345 小数点左移1位
    
            System.out.println(num4.negate());  // 返回"-num"
    
            System.out.println(num4.plus());  // 返回"+num"
    
            System.out.println(num4.precision()); // 5 返回精度值
    
            System.out.println(num4.scale());  // 3 返回小数位数
    
            System.out.println(num4.scaleByPowerOfTen(2)); // 乘以10^2
    
            System.out.println(num4.setScale(2,RoundingMode.UP));  // 指定舍入模式设置小数点位数
    
            System.out.println(num4.signum()); // 判断符号,正数返回1,负数返回-1
    
            System.out.println(num4.ulp()); // 0.001 0值返回1,其他返回精确到的最小单位
    
            System.out.println(num4.unscaledValue()); // 返回乘以10^this.scale的BigInteger,相当于去掉小数点
    
            System.out.println(num4.stripTrailingZeros()); // 去除尾部无效的0
    
            System.out.println(num4.toBigInteger());  // 返回BigInteger(小数部分被丢弃)
    
            System.out.println(num4.toEngineeringString()); // 返回工程计数字符串
    
            BigDecimal num5 = new BigDecimal("0.1234");
            BigDecimal num6 = num5.pow(32);
            System.out.println(num6.toString());    // 适当的时候会进行计数法表示的字符串
            System.out.println(num6.toPlainString()); // 不修饰本色显示字符串
    
            /**
             * 格式化
             */
            BigDecimal num7 = new BigDecimal("0.1234");
    
            NumberFormat currency = NumberFormat.getCurrencyInstance(); // 货币格式化引用
            NumberFormat percent = NumberFormat.getPercentInstance();  // 百分比格式化引用
            percent.setMaximumFractionDigits(2); // 百分比小数点后最多2位
    
            System.out.println(currency.format(num7));  // ¥0.12
            System.out.println(percent.format(num7));  // 12.34%
  • 相关阅读:
    UVA 408 (13.07.28)
    linux概念之用户,组及权限
    Java实现 蓝桥杯 历届试题 网络寻路
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 九宫重排
    Java实现 蓝桥杯 历届试题 九宫重排
  • 原文地址:https://www.cnblogs.com/jiazhongxin/p/12837564.html
Copyright © 2011-2022 走看看