• Java中的浮点数-科学计数法-加减乘除


      上次,提到“元转分”这个浮点数问题,boss倾向于手动把1.23元这种格式,转换成123分。
      
      但实际上,浮点数很容易遇到精度问题。
      
      比如,System.out.println(4.015 * 1000);结果就不会是4015。
      
      以前,总结的元转分的问题,没能考虑到所有的场景,今天补充点上次遗漏的。
      
      -5.09,如果金额是负数,应该是-500-9=-509,而不是-500+9=-441,这是上次的一个超级bug。
      
      另外,需要还有一个超级bug,“1045189788”转换成double类型的元时,结果变成了1.04。
      
      debug了好久,才发现以前代码的漏洞。
      
      1045189788这种比较大的浮点数,在传递过程中,是“科学计数法”表示的,类似“1.04E”,
      所以,最后转换出了问题。
      
      其实,我一直不建议boss采用这种人工截取计算的方式,需要考虑的场景太复杂,建议使用JDK内置的BigDecimal。
      
      经过实践,发现很不错。
      
      可以用double、string等多种原始类型,构造BigDecimal,再进行四则运算。
      
      使用BigDecimal的关键是,控制“标度”即“精度”,scale。
      
      算术运算结果的首选标度  运算 结果的首选标度 
    加 max(addend.scale(), augend.scale()) 
    减 max(minuend.scale(), subtrahend.scale()) 
    乘 multiplier.scale() + multiplicand.scale() 
    除 dividend.scale() - divisor.scale() 


      下面这个工具类,是从网上copy的,还是非常有价值的。
      
      import java.math.BigDecimal;


    /**
     * 消除加减乘除的精度,解决Float与Double类型进度不准确的问题.
     */
    public class DoubleUtil {
    /**
    * 加法运算

    * @param v1
    * @param v2
    * @return
    */
    public static double add(double v1, double v2) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    return b1.add(b2).doubleValue();
    }


    /**
    * 减法运算

    * @param v1
    * @param v2
    * @return
    */
    public static double sub(double v1, double v2) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    return b1.subtract(b2).doubleValue();
    }


    /**
    * 乘法运算

    * @param v1
    * @param v2
    * @return
    */
    public static double mul(double v1, double v2) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    return b1.multiply(b2).doubleValue();
    }


    /**
    * 除法运算

    * @param v1
    *            被除数
    * @param v2
    *            除数
    * @return 商
    */
    public static double div(double v1, double v2) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    return b1.divide(b2).doubleValue();
    }


    /**
    * 除法运算

    * @param v1
    *            被除数
    * @param v2
    *            除数
    * @return 商和余数
    */
    public static BigDecimal[] divideAndRemainder(double v1, double v2) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    BigDecimal[] arr = b1.divideAndRemainder(b2);
    return arr;
    }


    /**
    * 求商(向下舍入)

    * @param v1
    * @param v2
    * @return
    */
    public static BigDecimal divideToIntegralValue(double v1, double v2) {
    BigDecimal b1 = new BigDecimal(Double.toString(v1));
    BigDecimal b2 = new BigDecimal(Double.toString(v2));
    System.out.println("------------");
    return b1.divideToIntegralValue(b2);
    }


    public static void main(String[] args) {
    testUnPrecision();
    System.out.println("----------使用BigDecimal消除精度影响------------ "
    + DoubleUtil.add(0.05, 0.01));
    System.out.println(DoubleUtil.sub(1.0, 0.54));
    System.out.println(DoubleUtil.mul(4.015, 1000));
    System.out.println(DoubleUtil.div(12.3, 10));
    // 得到商和余数
    BigDecimal[] arr = DoubleUtil.divideAndRemainder(12.3, 10);
    System.out.println("得到商和余数");
    for (BigDecimal bigDecimal : arr) {
    System.out.println(bigDecimal);
    }
    System.out.println(DoubleUtil.divideToIntegralValue(4.5, 2));
    }


    /**
    * 不准确问题示例
    */
    private static void testUnPrecision() {
    System.out.println("--------Java自身的Double类型有精度损失----------");
    System.out.println(0.05 + 0.01);
    System.out.println(1.0 - 0.54);
    System.out.println(4.015 * 1000);
    System.out.println(12.3 / 100);
    }
    }

  • 相关阅读:
    [No0000C9]神秘的掐指一算是什么?教教你也会
    [No0000C8]英特尔快速存储IRST要不要装
    [No0000C7]windows 10桌面切换快捷键,win10
    [No0000C6]Visual Studio 2017 函数头显示引用个数
    [No0000C4]TortoiseSVN配置外部对比工具
    [No0000C5]VS2010删除空行
    [No0000C3]StarUML2 全平台破解方法
    [No0000C2]WPF 数据绑定的调试
    [No0000C1]Excel 删除空白行和空白列VBA代码
    [No0000C0]百度网盘真实地址解析(不用下载百度网盘)20170301
  • 原文地址:https://www.cnblogs.com/qitian1/p/6462860.html
Copyright © 2020-2023  润新知