首页 文章

Double vs. BigDecimal?

提问于
浏览
220

我必须计算一些浮点变量,我的同事建议我使用 BigDecimal 而不是 double ,因为它会更精确 . 但我想知道它是什么以及如何充分利用 BigDecimal

8 回答

  • -2

    BigDecimal 是表示数字的精确方式 . Double 具有一定的精度 . 使用各种大小的双精度(比如 d1=1000.0d2=0.001 )可能会导致 0.001 在求和时全部掉落,因为幅度的差异非常大 . 使用 BigDecimal 这不会发生 .

    BigDecimal 的缺点是's slower, and it'用这种方式编程算法要困难得多(由于 + - */ 没有过载) .

    如果您正在处理金钱,或精确是必须的,请使用 BigDecimal . 否则 Doubles 往往足够好 .

    我建议阅读 BigDecimalBigDecimal ,因为他们解释的事情比我在这里做得更好:)

  • 1

    我的英语不好,所以我在这里写一个简单的例子 .

    double a = 0.02;
        double b = 0.03;
        double c = b - a;
        System.out.println(c);
    
        BigDecimal _a = new BigDecimal("0.02");
        BigDecimal _b = new BigDecimal("0.03");
        BigDecimal _c = _b.subtract(_a);
        System.out.println(_c);
    

    节目输出:

    0.009999999999999998
    0.01
    

    有人还想用双? ;)

  • 6

    与double有两个主要区别:

    • 任意精度,与BigInteger类似,它们可以包含任意精度和大小的数量

    • Base 10而不是Base 2,BigDecimal是n * 10 ^ scale,其中n是任意大的有符号整数,scale可以被认为是向左或向右移动小数点的位数

    您应该使用BigDecimal进行货币计算的原因并不是它可以表示任何数字,而是它可以表示可以用十进制概念表示的所有数字,并且几乎包括货币世界中的所有数字(您永远不会转移1/3 $给某人) .

  • 38

    如果你想记下像十进制值那样的1/7值

    1/7 = 0.142857142857142857142857142857142857142857...
    

    无限序列142857.但由于你只能写下有限数量的数字,你将不可避免地引入舍入(或截断)错误 .

    不幸的是,像1/10或1/100这样的数字表示为具有小数部分的二进制数也具有无限小数的二进制数 .

    1/10 = binary 0.0001100110011001100110011001100110...
    

    双精度值存储为二进制数,因此可能仅通过将十进制数转换为二进制数来引入错误,甚至不进行任何算术运算 .

    另一方面,十进制数字(如 BigDecimal )按原样存储每个十进制数字 . 这意味着十进制类型在一般意义上并不比二进制浮点或固定点类型更精确(例如,它不能存储1/7而不会损失精度),但对于有限数量的数字给出的数字更准确十进制数字,通常是货币计算的情况 .

    Java的 BigDecimal 还有一个额外的好处,即它可以在小数点的两边有一个任意(但有限)的数字位数,仅受可用内存的限制 .

  • 328

    BigDecimal是Oracle的任意精度数值库 . BigDecimal是Java语言的一部分,适用于从财务到科学的各种应用程序(这就是上下文) .

    将双打用于某些计算没有任何问题 . 但是,假设您想要计算Math.Pi * Math.Pi / 6,即Riemann Zeta函数的值,实际参数为2(我正在研究的项目) . 浮点除法会给您带来一个圆角误差的痛苦问题 .

    另一方面,BigDecimal包含许多用于计算任意精度的表达式的选项 . 下面的Oracle文档中描述的add,multiply和divide方法在BigDecimal Java World中“取代”*和/:

    http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

    compareTo方法在while和for循环中特别有用 .

    但是,在使用BigDecimal的构造函数时要小心 . 在许多情况下,字符串构造函数非常有用 . 例如,代码

    BigDecimal onethird = new BigDecimal(“0.33333333333”);

    利用1/3的字符串表示来表示无限重复的数字到指定的准确度 . 舍入误差最有可能发生在JVM内部的某个深处,以致舍入误差不会干扰大多数实际计算 . 然而,从个人经验来看,我看到了四舍五入 . 从Oracle文档中可以看出,setScale方法在这些方面很重要 .

  • 11

    如果你正在处理计算,有关于如何计算和应该使用的精度的法律 . 如果你失败了,你会做一些违法的事情 . 唯一真正的原因是十进制情况的位表示不精确 . 罗勒只是简单地说,一个例子是最好的解释 . 只是为了补充他的例子,这是发生的事情:

    static void theDoubleProblem1() {
        double d1 = 0.3;
        double d2 = 0.2;
        System.out.println("Double:\t 0,3 - 0,2 = " + (d1 - d2));
    
        float f1 = 0.3f;
        float f2 = 0.2f;
        System.out.println("Float:\t 0,3 - 0,2 = " + (f1 - f2));
    
        BigDecimal bd1 = new BigDecimal("0.3");
        BigDecimal bd2 = new BigDecimal("0.2");
        System.out.println("BigDec:\t 0,3 - 0,2 = " + (bd1.subtract(bd2)));
    }
    

    输出:

    Double:  0,3 - 0,2 = 0.09999999999999998
    Float:   0,3 - 0,2 = 0.10000001
    BigDec:  0,3 - 0,2 = 0.1
    

    我们也有:

    static void theDoubleProblem2() {
        double d1 = 10;
        double d2 = 3;
        System.out.println("Double:\t 10 / 3 = " + (d1 / d2));
    
        float f1 = 10f;
        float f2 = 3f;
        System.out.println("Float:\t 10 / 3 = " + (f1 / f2));
    
        // Exception! 
        BigDecimal bd3 = new BigDecimal("10");
        BigDecimal bd4 = new BigDecimal("3");
        System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4)));
    }
    

    给我们输出:

    Double:  10 / 3 = 3.3333333333333335
    Float:   10 / 3 = 3.3333333
    Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion
    

    但:

    static void theDoubleProblem2() {
        BigDecimal bd3 = new BigDecimal("10");
        BigDecimal bd4 = new BigDecimal("3");
        System.out.println("BigDec:\t 10 / 3 = " + (bd3.divide(bd4, 4, BigDecimal.ROUND_HALF_UP)));
    }
    

    有输出:

    BigDec:  10 / 3 = 3.3333
    
  • -8
    package j2ee.java.math;
    
    /**
     *      Generated from IDL definition of "valuetype "BigDecimal""
     *      TomORB IDL compiler v1.0
     */
    
    public abstract class BigDecimal extends j2ee.java.lang.Number implements org.omg.CORBA.portable.StreamableValue, j2ee.java.lang.Comparable
    
    {
    
            private String[] _truncatable_ids = {"RMI:java.math.BigDecimal:11F6D308F5398BBD:54C71557F981284F"};
    
    
    
            protected int scale_;
    
            protected j2ee.java.math.BigInteger intVal;
    
    
    
            /* constants */
    
            int ROUND_UP = 0;
    
            int ROUND_DOWN = 1;
    
            int ROUND_CEILING = 2;
    
            int ROUND_FLOOR = 3;
    
            int ROUND_HALF_UP = 4;
    
            int ROUND_HALF_DOWN = 5;
    
            int ROUND_HALF_EVEN = 6;
    
            int ROUND_UNNECESSARY = 7;
    
    
    
            public abstract int _hashCode();
    
    
    
            public abstract int scale();
    
    
    
            public abstract int signum();
    
    
    
            public abstract boolean _equals(org.omg.CORBA.Any arg0);
    
    
    
            public abstract java.lang.String _toString();
    
    
    
            public abstract j2ee.java.math.BigDecimal abs();
    
    
    
            public abstract j2ee.java.math.BigDecimal negate();
    
    
    
            public abstract j2ee.java.math.BigDecimal movePointLeft(int arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal movePointRight(int arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal setScale(int arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal setScale(int arg0, int arg1);
    
    
    
            public abstract j2ee.java.math.BigDecimal valueOf(long arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal valueOf(long arg0, int arg1);
    
    
    
            public abstract int compareTo(j2ee.java.math.BigDecimal arg0);
    
    
    
            public abstract j2ee.java.math.BigInteger toBigInteger();
    
    
    
            public abstract j2ee.java.math.BigInteger unscaledValue();
    
    
    
            public abstract j2ee.javax.rmi.CORBA.ClassDesc classU0024(java.lang.String arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal add(j2ee.java.math.BigDecimal arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal max(j2ee.java.math.BigDecimal arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal min(j2ee.java.math.BigDecimal arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal multiply(j2ee.java.math.BigDecimal arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal subtract(j2ee.java.math.BigDecimal arg0);
    
    
    
            public abstract j2ee.java.math.BigDecimal divide(j2ee.java.math.BigDecimal arg0, int arg1);
    
    
    
            public abstract j2ee.java.math.BigDecimal divide(j2ee.java.math.BigDecimal arg0, int arg1, int arg2);
    
    
    
            public void _write (org.omg.CORBA.portable.OutputStream os)
    
            {
    
                   super._write( os );
    
                   os.write_long(scale_);
    
             ((org.omg.CORBA_2_3.portable.OutputStream)os).write_value( new java.lang.String("intVal") );
    
            }
    
    
    
            public void _read (final org.omg.CORBA.portable.InputStream os)
            {
                   super._read( os );
    
                   scale_=os.read_long();
    
             intVal=(j2ee.java.math.BigInteger)((org.omg.CORBA_2_3.portable.InputStream)os).read_value ( "RMI:java.math.BigInteger:E2F79B6E7A470003:8CFC9F1FA93BFB1D".toString() );
            }
    
            public String[] _truncatable_ids()
            {
                   return _truncatable_ids;
            }
    
            public org.omg.CORBA.TypeCode _type()
            {
                   return j2ee.java.math.BigDecimalHelper.type();
            }
    }
    
  • 128

    原始数字类型对于在内存中存储单个值很有用 . 但是当处理使用double和float类型的计算时,舍入存在问题 . 这是因为内存表示不使用所有64位 . 它只存储它认为数字的重要部分 . 因此,当您将float或double类型的值一起添加时,可能会出现错误的值 . 可能是这个视频https://youtu.be/EXxUSz9x7BM会解释更多

相关问题