当前位置:  开发笔记 > 编程语言 > 正文

在Java中保留double的精度

如何解决《在Java中保留double的精度》经验,为你挑选了9个好方法。

正如其他人所提到的BigDecimal,如果你想要一个11.4的精确表示,你可能想要使用这个类.

现在,解释为什么会发生这种情况:

floatdouble在Java原始类型浮点数字,其中该数字存储为部分和指数的二进制表示.

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

1位表示符号(正或负).

指数为11位.

有效数字为52位(小数部分为二进制).

组合这些部分以产生double值的表示.

(来源:维基百科:双精度)

有关如何在Java中处理浮点值的详细说明,请参见部分4.2.3: Java语言规范的浮点类型,格式和值.

byte,char,int,long类型的定点数字,这是数字的精确representions.与定点数不同,浮点数有时会(可以安全地假定"大部分时间")不能返回数字的精确表示.这就是为什么你最终得到11.399999999999的结果5.6 + 5.8.

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

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

从类的Java API Reference BigDecimal:

不可变的,任意精度的带符号十进制数.BigDecimal由任意精度整数非标度值和32位整数标度组成.如果为零或正数,则比例是小数点右侧的位数.如果是负数,则将数字的未缩放值乘以10来表示比例的否定.因此,BigDecimal表示的数字的值是(unscaledValue×10 ^ -scale).

Stack Overflow上有很多关于浮点数及其精度的问题.以下是可能感兴趣的相关问题列表:

为什么我看到一个双变量初始化为某个值,如21.4为21.399999618530273?

如何在C++中打印真正的大数字

浮点是如何存储的?什么时候重要?

使用Float或Decimal作为会计应用程序的美元金额?

如果你真的想了解浮点数的细节,请看看每个计算机科学家应该知道的关于浮点运算的内容.



1> coobird..:

正如其他人所提到的BigDecimal,如果你想要一个11.4的精确表示,你可能想要使用这个类.

现在,解释为什么会发生这种情况:

floatdouble在Java原始类型浮点数字,其中该数字存储为部分和指数的二进制表示.

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

1位表示符号(正或负).

指数为11位.

有效数字为52位(小数部分为二进制).

组合这些部分以产生double值的表示.

(来源:维基百科:双精度)

有关如何在Java中处理浮点值的详细说明,请参见部分4.2.3: Java语言规范的浮点类型,格式和值.

byte,char,int,long类型的定点数字,这是数字的精确representions.与定点数不同,浮点数有时会(可以安全地假定"大部分时间")不能返回数字的精确表示.这就是为什么你最终得到11.399999999999的结果5.6 + 5.8.

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

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

从类的Java API Reference BigDecimal:

不可变的,任意精度的带符号十进制数.BigDecimal由任意精度整数非标度值和32位整数标度组成.如果为零或正数,则比例是小数点右侧的位数.如果是负数,则将数字的未缩放值乘以10来表示比例的否定.因此,BigDecimal表示的数字的值是(unscaledValue×10 ^ -scale).

Stack Overflow上有很多关于浮点数及其精度的问题.以下是可能感兴趣的相关问题列表:

为什么我看到一个双变量初始化为某个值,如21.4为21.399999618530273?

如何在C++中打印真正的大数字

浮点是如何存储的?什么时候重要?

使用Float或Decimal作为会计应用程序的美元金额?

如果你真的想了解浮点数的细节,请看看每个计算机科学家应该知道的关于浮点运算的内容.


事实上,通常有53个有效位,因为"十进制"点之前的1对于除了非规范化值之外的所有值都是隐含的,从而提供了额外的精度.例如3被存储为(1.)1000 ... x 2 ^ 1而0.5存储为(1.)0000 ... x 2 ^ -1当该值被非规范化时(所有指数位为零)可以,并且通常将更少有效数字,例如1 x 2 ^ -1030存储为(0.)00000001 x 2 ^ -1022,因此已按比例牺牲了七位有效数字.
@PeterLawrey它有15个十进制*位*的精度,如果它们都是*小数点之前的*.由于十进制和二进制分数的不可通约性,小数点后可能发生任何事情.

2> Stephen Cano..:

例如,当您输入双33.33333333333333精度数时,您获得的值实际上是最接近的可表示的双精度值,它恰好是:

33.3333333333333285963817615993320941925048828125

除以100得出:

0.333333333333333285963817615993320941925048828125

它也不能表示为双精度数,因此它再次舍入到最接近的可表示值,这恰好是:

0.3333333333333332593184650249895639717578887939453125

当你打印出这个值时,它会再次舍入到17个十进制数字,给出:

0.33333333333333326


对于将来正在阅读这篇文章的人来说,并且对于为什么答案与问题无关而感到困惑:一些主持人决定合并我(和其他人)回答的问题,这个问题相当不同.

3> Viral Shah..:

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

编写加,减,乘和除的方法以及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);
    }
}

}


ViralShah:在处理数学运算时,它还可能引入浮点错误.鉴于此练习的目的是避免这一点,改变它似乎是明智的.
分数的这种实现存在问题,因为它不会将它们简化为最简单的形式.2/3*1/2给2/6你真正想要的答案是1/3.理想情况下,在构造函数中,您希望找到分子和除数的gcd并将其除以.

4> Steve Jessop..:

如果你使用有限精度的十进制算术,并且想要处理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.FormatterString.format.在格式字符串中,指定精度小于double的完整精度.对于10个有效数字,例如11.399999999999是11.4,因此在二进制结果非常接近仅需要几个小数位的值的情况下,结果将几乎同样准确且更易于阅读.

要指定的精度取决于你对数字做了多少数学运算 - 一般来说,你做的越多,误差就越多,但是有些算法比其他算法累积得更快(它们被称为"不稳定"的反对舍入误差的"稳定").如果您所做的只是添加一些值,那么我猜测只丢一个小数位的精度就可以解决问题.实验.


不,做*不*使用带货币值的双倍!你需要精确的金钱,而不是使用BigDecimal.否则,你的答案是好的.你需要精确的东西,使用BigDecimal,如果精度不重要,你可以使用float或double.

5> Vinny..:

如果你真的需要精确数学,你可能想要研究使用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



6> Dustin..:

很确定你可以把它变成一个三行的例子.:)

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



7> Draemon..:

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

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

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

会给你:

11.40



8> dan04..:

你不能,因为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)

如果你正在使用金钱,那么你真正想要的是十进制定点.存储整数分数或任何最小单位的货币.

(非常不可思议)如果需要超过53个有效位(15-16位有效数字)的精度,则使用高精度浮点类型,如BigDecimal.


wrongusername:不,你没有.它只是以这种方式显示.使用"%.17g"格式(或更好的是,"%.51g")来查看真实答案.

9> John..:

你遇到了double类型的精度限制.

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

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有