java中带double的浮点保留精度

imzjd6km  于 2021-06-30  发布在  Java
关注(0)|答案(22)|浏览(400)
public class doublePrecision {
    public static void main(String[] args) {

        double total = 0;
        total += 5.6;
        total += 5.8;
        System.out.println(total);
    }
}

上面的代码打印:

11.399999999999

我怎样才能把它打印出来(或者作为11.4使用)?

bvjxkvbb

bvjxkvbb1#

正如其他人提到的,您可能希望使用 BigDecimal 类,如果您想得到11.4的精确表示。
现在,我们来解释一下为什么会这样:
这个 float 以及 double java中的基本类型是浮点数,其中的数字存储为分数和指数的二进制表示形式。
更具体地说,双精度浮点值,例如 double 类型是64位值,其中:
1位表示符号(正或负)。
11位表示指数。
52位表示有效数字(小数部分为二进制)。
这些部件结合在一起形成一个整体 double 值的表示。
(来源:维基百科:双精度)
有关如何在java中处理浮点值的详细描述,请参阅java语言规范的第4.2.3节:浮点类型、格式和值。
这个 byte , char , int , long 类型是定点数,是数字的精确表示。与定点数字不同,浮点数字有时(可以肯定的是“大多数时间”)无法返回数字的精确表示。这就是为什么你最终 11.399999999999 由于 5.6 + 5.8 .
当需要精确的值时,例如1.5或150.1005,您需要使用一种定点类型,它将能够精确地表示数字。
正如已经多次提到的,java有一个 BigDecimal 类,它将处理非常大的数字和非常小的数字。
来自 BigDecimal 班级:
不可变的、任意精度的有符号十进制数。bigdecimal由任意精度整数(未标度值)和32位整数标度组成。如果为零或正,则刻度为小数点右侧的位数。如果为负数,则数字的未标度值乘以10,即标度的负数的幂。因此,由bigdecimal表示的数字的值是(unscaledvalue× 10^-比例)。
在堆栈溢出问题上,一直存在着许多与浮点数及其精度有关的问题。以下是可能感兴趣的相关问题列表:
为什么我会看到一个双变量被初始化为21.4这样的值21.399999618530273?
如何在c中打印真正大的数字++
浮点是如何存储的?什么时候重要?
使用浮动或小数作为会计应用程序美元金额?
如果你真的想深入了解浮点数的细节,看看每个计算机科学家都应该知道的浮点数算法。

dluptydi

dluptydi2#

例如,当您输入一个双数时, 33.33333333333333 ,得到的值实际上是最接近的可表示双精度值,确切地说:

33.3333333333333285963817615993320941925048828125

除以100得出:

0.333333333333333285963817615993320941925048828125

它也不能表示为双精度数,所以再次四舍五入到最接近的可表示值,即:

0.3333333333333332593184650249895639717578887939453125

当您打印出这个值时,它会再次四舍五入到17位小数,给出:

0.33333333333333326
y4ekin9u

y4ekin9u3#

如果您只想将值作为分数进行处理,那么可以创建一个包含分子和分母字段的分数类。
写加法、减法、乘法和除法以及todouble方法。这样可以避免计算过程中出现浮动。
编辑:快速实施,

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);
    }
}

}
s8vozzvw

s8vozzvw4#

注意,如果您使用有限精度的十进制算术,并且希望处理1/3,那么您也会遇到同样的问题:0.333333333*3是0.999999999,而不是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.3999999999是11.4,因此在二进制结果非常接近只需要几个小数位的值的情况下,结果几乎同样准确,更便于人阅读。
指定的精度在某种程度上取决于你对数字所做的运算量——一般来说,你做得越多,累积的误差就越大,但有些算法的累积速度要比其他算法快得多(它们被称为“不稳定”而不是“稳定”的舍入误差)。如果你所做的只是添加一些值,那么我猜只要去掉小数点后一位就可以解决问题。实验。

up9lanfz

up9lanfz5#

如果您真的需要精确数学,您可能需要研究使用java的java.math.bigdecimal类。这是一篇来自oracle/sun的关于bigdecimal的好文章。虽然你永远不能像某人所说的那样代表1/3,但你可以决定你想要的结果到底有多精确。setscale()是您的朋友….:)
好吧,因为我现在手头的时间太多了,下面是一个与您的问题相关的代码示例:

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

    }
}

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

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
5f0d552i

5f0d552i6#

很确定你可以把它变成一个三行的例子。:)
如果您想要精确的精度,请使用bigdecimal。否则,可以使用int乘以10^的任意精度。

zzoitvuj

zzoitvuj7#

正如其他人所指出的,并不是所有的十进制值都可以表示为二进制,因为十进制是基于10的幂,二进制是基于2的幂。
如果精度很重要,请使用bigdecimal,但如果您只是想要友好的输出:

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

将为您提供:

11.40
vxbzzdmp

vxbzzdmp8#

你正面临双重类型的精度限制。
数学有一些任意精度的算术工具。

djp7away

djp7away9#

你不能,因为7.3没有二进制的有限表示。最接近的是2054767329987789/2**48=7.3+1/1407374883553280。
看一看http://docs.python.org/tutorial/floatingpoint.html 进一步解释(它在python网站上,但是java和c++有相同的“问题”。)
解决方案取决于您的问题具体是什么:
如果你只是不喜欢看到那些杂音数字,那就修改你的字符串格式。不要显示超过15位有效数字(或7表示浮点)。
如果数字的不精确性破坏了“if”语句,那么应该写if(abs(x-7.3)<容差),而不是if(x==7.3)。
如果你用的是钱,那么你可能真正想要的是十进制定点。存储一个整数,单位是分或任何最小的货币单位。
(不太可能)如果需要超过53个有效位(15-16个有效位)的精度,则使用高精度浮点类型,如bigdecimal。

p1tboqfb

p1tboqfb10#

使用java.math.bigdecimal
double在内部是二进制分数,所以它们有时不能精确地表示十进制分数。

b5buobof

b5buobof11#

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
}
bprjcwpo

bprjcwpo12#

把所有的东西都乘以100,然后储存在一个很长的分币里。

sxpgvts3

sxpgvts313#

计算机以二进制形式存储数字,实际上不能准确地表示33.333或100.0之类的数字。这是使用双打的技巧之一。在将答案展示给用户之前,您必须对其进行四舍五入。幸运的是,在大多数应用程序中,您不需要那么多小数位。

wi3ka0sx

wi3ka0sx14#

浮点数与实数的不同之处在于,对于任何给定的浮点数,都有一个更高的浮点数。与整数相同。1和2之间没有整数。
无法将1/3表示为浮点数。它下面有个浮子,上面有个浮子,它们之间有一定的距离。三分之一在这个空间里。
apfloat for java声称可以处理任意精度的浮点数,但我从未使用过它。可能值得一看。http://www.apfloat.org/apfloat_java/
在java浮点高精度库之前,这里也提出了类似的问题

62lalag4

62lalag415#

double是java源代码中十进制数的近似值。您看到了double(二进制编码的值)和源代码(十进制编码的)之间不匹配的结果。
java正在生成最接近的二进制近似值。可以使用java.text.decimalformat来显示外观更好的十进制值。

相关问题