在Java中使用double保持精度

在Java中使用double保持精度,java,floating-point,double,precision,Java,Floating Point,Double,Precision,上述代码打印: 11.399999999999 我怎样才能把它打印出来或者作为11.4版本使用呢?将所有内容乘以100,然后以美分的形式存储起来。很肯定你可以把它做成一个三行的例子: 如果您想要精确的精度,请使用BigDecimal。否则,可以使用整数乘以10^的任意精度。double是Java源代码中十进制数的近似值。您看到了二进制编码的double值和十进制编码的源代码之间不匹配的结果 Java正在生成最接近的二进制近似值。您可以使用java.text.DecimalFormat来显示外观更

上述代码打印:

11.399999999999
我怎样才能把它打印出来或者作为11.4版本使用呢?

将所有内容乘以100,然后以美分的形式存储起来。

很肯定你可以把它做成一个三行的例子:

如果您想要精确的精度,请使用BigDecimal。否则,可以使用整数乘以10^的任意精度。

double是Java源代码中十进制数的近似值。您看到了二进制编码的double值和十进制编码的源代码之间不匹配的结果


Java正在生成最接近的二进制近似值。您可以使用java.text.DecimalFormat来显示外观更好的十进制值。

使用BigDecimal。它甚至允许您指定舍入规则,如ROUND_HALF_偶数,这将通过舍入到偶数邻居(如果两者的距离相同)来最小化统计误差;i、 e.1.5和2.5四舍五入到2。

观察到,如果您使用有限精度的十进制算法,并且想要处理1/3,您会遇到同样的问题:0.333333333*3是0.99999999,而不是1.00000000

不幸的是,5.6、5.8和11.4并不是二进制的整数,因为它们涉及五分之一。所以它们的浮点表示并不精确,正如0.3333不完全是1/3

如果您使用的所有数字都是非循环小数,并且希望得到精确的结果,请使用BigDecimal。或者正如其他人所说,如果你的价值观就像金钱一样,它们都是0.01或0.001的倍数,或者别的什么,那么把所有的东西乘以10的固定幂,然后使用int或long加法和减法是微不足道的:小心乘法

但是,如果您对二进制计算感到满意,但只想以稍微友好的格式打印出来,请尝试java.util.Formatter或String.format。在格式字符串中,指定小于双精度整数的精度。对于10个有效数字,比如说,11.399999999是11.4,因此,如果二进制结果非常接近只需要几个小数位的值,那么结果几乎同样准确,更容易让人阅读


指定的精度在一定程度上取决于你对数字的运算量——一般来说,运算量越大,累积的误差就越大,但有些算法的累积速度要比其他算法快得多——它们被称为不稳定的,而不是关于舍入误差的稳定的。如果您所做的只是添加一些值,那么我猜只需删除精度的小数点后一位就可以解决问题。实验。

正如其他人所提到的,如果您想获得11.4的精确表示,您可能需要使用该类

现在,我们来解释一下为什么会发生这种情况:

Java中的float和double原语类型是数字,数字存储为分数和指数的二进制表示形式

更具体地说,双精度浮点值(如双精度类型)是64位值,其中:

1位表示正负号。 指数为11位。 52位为有效数字,小数部分为二进制。 将这些部分组合起来以生成值的双重表示形式

资料来源:

有关如何在Java中处理浮点值的详细说明,请参阅Java语言规范的

byte、char、int和long类型都是数字,它们是数字的精确表示。与定点数字不同,浮点数有时可以安全地假定在大多数情况下无法返回数字的精确表示形式。这就是为什么5.6+5.8的结果是11.399999999

当需要精确的值(例如1.5或150.1005)时,您需要使用一种定点类型,它能够精确地表示数字

正如已经多次提到的,Java有一个类可以处理非常大的数字和非常小的数字

根据BigDecimal类的Java API参考:

一成不变, 任意精度有符号十进制 数字。BigDecimal由一个 任意精度整数无标度 值和32位整数刻度。如果 零或正,刻度为 文本右侧的位数 小数点。如果为负数,则为 数字的未标度值为 乘以10,等于 规模的否定。价值 由 因此,BigDecimal是非标度值 ×10^-比例

关于堆栈溢出,有许多问题与浮点数及其精度有关。以下是可能感兴趣的相关问题列表:


如果您真的想深入了解浮点数的细节,请看一看。

正如其他人所指出的,并不是所有的十进制值都可以被表示 因为十进制是基于10的幂,二进制是基于2的幂

如果精度很重要,请使用BigDecimal,但如果您只是想要友好的输出:

public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}
public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}
将为您提供:

System.out.printf("%.2f\n", total);

看看BigDecimal,它处理类似于浮点运算的问题

新呼叫将如下所示:

11.40

使用setScale设置要使用的小数位数精度。

使用java.math.BigDecimal


double在内部是二进制分数,因此它们有时不能将十进制分数表示为精确的十进制。

您不能,因为7.3没有二进制的有限表示。最接近的是2054767373299987789/2**48=7.3+1/1407374883553280

请看一看以获得进一步的解释。它在Python网站上,但是java和C++有相同的问题。 解决方案取决于您的问题具体是什么:

如果您只是不喜欢看到所有这些噪声数字,那么请修复字符串格式。显示的有效数字不能超过15位,浮点数不能超过7位。 如果数字的不精确性破坏了If语句,那么应该编写If-absx-7.3<容差,而不是If x==7.3。 如果你用的是钱,那么你可能真正想要的是十进制定点。存储一个整数分或任何最小的货币单位。 如果需要超过53个有效位15-16个有效位的精度,则不太可能使用高精度浮点类型,如BigDecimal。
您遇到了类型double的精度限制


Java.Math有一些任意精度的算术工具。

计算机以二进制形式存储数字,实际上无法准确地表示33.333或100.0等数字。这是使用双打的一个棘手问题。在将答案展示给用户之前,您必须将答案四舍五入。幸运的是,在大多数应用程序中,您无论如何都不需要那么多小数。

浮点数不同于实数,因为对于任何给定的浮点数,都有一个更高的浮点数。与整数相同。1和2之间没有整数

无法将1/3表示为浮点数。它下面有一个浮子,上面有一个浮子,它们之间有一定的距离。三分之一在那个空间里

Apfloat for Java声称可以处理任意精度的浮点数,但我从未使用过它。也许值得一看。

在此之前也曾提出过类似的问题

当您输入一个双精度数字时,例如33.33333,您得到的值实际上是最接近的可表示双精度值,即:

term[number].coefficient.add(co);
0.333333333333333285963817615993320941925048828125
除以100得到:

33.3333333333333285963817615993320941925048828125
它也不能表示为双精度数字,因此再次将其四舍五入到最接近的可表示值,即:

term[number].coefficient.add(co);
0.333333333333333285963817615993320941925048828125
当您打印出该值时,它会再次四舍五入到17位小数,给出:

0.3333333333333332593184650249895639717578887939453125

如果您真的需要精确数学,您可能需要研究使用java的java.math.BigDecimal类。这里有一篇来自Oracle/Sun的好文章。虽然你永远不能像某人提到的那样代表1/3,但你可以决定你想要的结果到底有多精确。setScale是您的朋友..:

好的,因为我现在手头有太多的时间,这里有一个与您的问题相关的代码示例:

0.33333333333333326
为了插入我最喜欢的新语言Groovy,这里有一个更简洁的例子:

import java.math.BigDecimal;
/**
 * Created by a wonderful programmer known as:
 * Vincent Stoessel
 * xaymaca@gmail.com
 * on Mar 17, 2010 at  11:05:16 PM
 */
public class BigUp {

    public static void main(String[] args) {
        BigDecimal first, second, result ;
        first = new BigDecimal("33.33333333333333")  ;
        second = new BigDecimal("100") ;
        result = first.divide(second);
        System.out.println("result is " + result);
       //will print : result is 0.3333333333333333


    }
}

如果您只想将值作为分数进行处理,那么可以创建一个包含分子和分母字段的分数类

写加法、减法、乘法和除法以及toDouble方法。这样可以避免计算过程中出现浮动

编辑:快速实施

import java.math.BigDecimal

def  first =   new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")


println "result is " + first/second   // will print: result is 0.33333333333333

不要浪费你的精力使用BigDecimal。99.99999%的情况下你不需要它。java double类型是cource近似值,但在几乎所有情况下,它都足够精确。请注意,在第14个有效数字处有一个错误。这真是微不足道

要获得良好的输出,请使用:


为什么不在数学课上使用四舍五入法呢

private void getRound() {
    // this is very simple and interesting 
    double a = 5, b = 3, c;
    c = a / b;
    System.out.println(" round  val is " + c);

    //  round  val is  :  1.6666666666666667
    // if you want to only two precision point with double we 
            //  can use formate option in String 
           // which takes 2 parameters one is formte specifier which 
           // shows dicimal places another double value 
    String s = String.format("%.2f", c);
    double val = Double.parseDouble(s);
    System.out.println(" val is :" + val);
    // now out put will be : val is :1.67
}

如果您除了使用双精度值之外别无选择,可以使用以下代码

// The number of 0s determines how many digits you want after the floating point
// (here one digit)
total = (double)Math.round(total * 10) / 10;
System.out.println(total); // prints 11.4

简短回答:始终使用BigDecimal,并确保您使用的构造函数带有字符串参数,而不是双精度参数

回到您的示例,下面的代码将按照您的意愿打印11.4

public static double sumDouble(double value1, double value2) {
    double sum = 0.0;
    String value1Str = Double.toString(value1);
    int decimalIndex = value1Str.indexOf(".");
    int value1Precision = 0;
    if (decimalIndex != -1) {
        value1Precision = (value1Str.length() - 1) - decimalIndex;
    }

    String value2Str = Double.toString(value2);
    decimalIndex = value2Str.indexOf(".");
    int value2Precision = 0;
    if (decimalIndex != -1) {
        value2Precision = (value2Str.length() - 1) - decimalIndex;
    }

    int maxPrecision = value1Precision > value2Precision ? value1Precision : value2Precision;
    sum = value1 + value2;
    String s = String.format("%." + maxPrecision + "f", sum);
    sum = Double.parseDouble(s);
    return sum;
}

不,不要将double与货币值一起使用!你需要金钱的精确性,用BigDecimal代替。否则,你的答案是好的。任何需要精度的东西,都可以使用BigDecimal,如果精度不是那么重要,可以使用float或double。这个问题不再说明或暗示涉及金钱。我特别建议使用BigDecimal或整数来表示货币。有什么问题吗?等于不使用double表示货币,就是不使用BigDecimal或double表示三分之一。但是萨默蒂

问题涉及分裂,在这种情况下,不能被所有分母的所有素数因子整除的所有基都是同样糟糕的。如果精度小于4,则9999=1digits@Draemon-看看上次编辑前的帖子-所有shoppingTotal、calcGST和calcPST的东西在我看来都像钱。7.3可能没有二进制的有限表示形式,但是当我在C++中尝试同样的东西时,我确实得到了-7.3用户名:不,你没有。它就是这样显示的。使用%.17g或更好的格式,%.51g来查看真正的答案。-1表示盲目推荐BigDecimal。如果你实际上不需要十进制算法,也就是说,如果你是用钱来计算的,那么BigDecimal对你没有帮助。它并不能解决所有的浮点错误:您仍然需要处理1/3*3=0.999999999999999999999999999和sqrt2**2=1.999999999999999999999999。此外,BigDecimal会带来巨大的速度损失。更糟糕的是,由于Java缺少运算符重载,您必须重写所有代码。@dan04-如果您用金钱进行计算,为什么要在知道其固有错误的情况下使用浮点表示法。。。。因为没有分数,你可以用十进制来计算分数,而不是用近似的美元,你就有了精确的分数。如果你真的想要分的分数,用一个长的,然后计算出几千分。此外,OP没有提到无理数,他所关心的只是加法。回答之前一定要仔细阅读这篇文章,理解问题所在,这样可能会让你省去一些尴尬。@Newtopian:我没有什么好尴尬的。OP没有提到钱,也没有任何迹象表明他的问题有任何固有的小数。@dan04-没有OP没有。。。你这样做了,并且盲目地断章取义地给出了一个完全可以接受的答案,因为提供的细节太少了。我正在做一些赔率计算,我希望有尽可能高的精确度。但我知道有一些限制。。。例如java.math包。分子和分母应该是整数吗?为什么需要浮点精度?我想这不是必须的,但它可以避免在toDouble函数中强制转换,因此代码的可读性更好。ViralShah:在处理数学运算时,它还可能引入浮点错误。考虑到本练习的目的是避免出现这种情况,因此修改它似乎是谨慎的。出于上述Samir Talwar提到的原因,编辑为使用整数而不是双精度。分数的这种实现存在问题,因为它不能将分数简化为最简单的形式。2/3*1/2给出2/6,你真正想要的答案是1/3。理想情况下,在构造函数中,你需要找到分子和除数的gcd,然后除以它们。我认为他担心的是输出,而不是数字精度。如果你除以三,大十进制就没有用了。它甚至会让事情变得更糟……你永远不应该用浮点来赚钱。我见过一个承包商在接受指示的情况下违反了这一规则。对于任何将来阅读这篇文章并对答案与问题无关感到困惑的人来说:一些主持人决定将我和其他人回答的问题合并在一起,这是完全不同的,问题。你如何知道确切的双精度值?@mikeyaworski参见双精度示例事实上,通常有53个有效位,因为小数点前的1表示除非规范化值外的所有值,从而提供额外的精度位。e、 g.3存储为1.1000。。。x 2^1,而0.5存储为1.0000。。。x 2^-1当值被反规范化时,所有指数位都为零,可以而且通常会,有效位数要少一些,例如,1 x 2^-1030存储为0.00000001 x 2^-1022,因此在缩放时牺牲了七个有效位数。应注意的是,在这种情况下,虽然BigDecimal比double慢得多,但不需要,因为double有15位小数精度,你只需要四舍五入。@PeterLawrey它有15位精度的小数位数,如果它们都在小数点之前。小数点后任何事情都可能发生,因为小数和二进制分数的不可通约性。@EJP您是对的,它大约有15位有效精度数字。它可以是16,但更安全的假设是15或14。@PeterLawrey EJP的更正是因为我的问题:你能详细说明为什么它不完全是15,以及它可以是16或14的情况吗?相关:
        /*
        0.8                     1.2
        0.7                     1.3
        0.7000000000000002      2.3
        0.7999999999999998      4.2
        */
        double adjust = fToInt + 1.0 - orgV;
        
        // The following two lines works for me. 
        String s = String.format("%.2f", adjust);
        double val = Double.parseDouble(s);

        System.out.println(val); // output: 0.8, 0.7, 0.7, 0.8