java Float 和 BigDecimal 精度差异

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11557839/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:33:51  来源:igfitidea点击:

Float and BigDecimal precision difference

javafloating-pointbigdecimal

提问by

public static void main(String[] args) {
    // TODO Auto-generated method stub
    BigDecimal foo,foo1;
    foo=BigDecimal.valueOf(3.1);
    foo1=BigDecimal.valueOf(3.1f);

    System.out.println(foo);
    System.out.println(foo1);

}

RESULT:
3.1
3.0999999046325684

Why they are different result? I am using JDK1.7.0_03

结果:
3.1
3.0999999046325684

为什么他们是不同的结果?我使用的是 JDK1.7.0_03

采纳答案by dacwe

3.1defines a doublewhile 3.1fdefines a float. What you see is the problem the floathas of representing that value (float uses "only" 32-bits and double 64-bits).

3.1定义了一个doublewhile3.1f定义了一个float。您看到的是float表示该值的问题(浮点数“仅”使用 32 位和双 64 位)。

If you want to define a 3.1exactly using BigDecimaluse the Stringconstructor:

如果你想定义一个3.1完全BigDecimal使用的String构造函数:

BigDecimal foo = new BigDecimal("3.1");
System.out.println(foo);

Output:

输出:

3.1

回答by Peter Lawrey

floatand doubleare different types with different precisions.

float并且double是具有不同精度的不同类型。

BigDecimal.valueOf(double) can correct for the representation error in doublebut not that in float

BigDecimal.valueOf(double) 可以纠正 indouble但不能纠正表示错误float

IMHO don't use floatunless you have a veryreason to do so.

恕我直言,不要使用float,除非你有非常的理由这样做。

回答by Matt

The problem is that for both float and double, you are using 32 and 64 bits respectively for representation of both the integer and decimal part of the number. The problem comes in when you try to represent a fractional value which doesn't really have an accurate decimal representation in binary bits.

问题是,对于 float 和 double,您分别使用 32 位和 64 位来表示数字的整数部分和小数部分。当您尝试表示一个小数值时,问题就出现了,而该小数值在二进制位中实际上没有准确的十进制表示。

Take .1 for example, there's no way to exactly represent this in base 2, any more than there is a way to accurately represent 1/3 in base 10.

以 0.1 为例,没有办法在基数 2 中准确表示它,就像有一种方法可以在基数 10 中准确表示 1/3。

So java uses some tricks so that when you say:

所以java使用了一些技巧,所以当你说:

float f = 3.1;
System.out.println(f);

It prints out the right number. However, when you start doing arithmetic with these values, you end up with rounding errors.

它打印出正确的数字。但是,当您开始使用这些值进行算术运算时,最终会出现舍入错误。

BigDecimal is accurate because it uses a different representation. It internally stores a BigInteger (which uses an int[] to represent huge numbers). It then uses a precision value to tell it how many of those integer digits are are after the decimal point.

BigDecimal 是准确的,因为它使用不同的表示。它在内部存储一个 BigInteger(它使用一个 int[] 来表示巨大的数字)。然后它使用一个精度值来告诉它有多少整数位在小数点后。

For instance, the value 3.1 would be represented in a BigDecimal as 31,precision=1 For this reason, BigDecimal doesn't suffer from the same rounding issues a float and double.

例如,值 3.1 在 BigDecimal 中将表示为 31,precision=1 出于这个原因,BigDecimal 不会遇到相同的舍入问题,即浮点数和双精度数。

However, when you use a float/double value to initialize a BigDecimal, the same rounding error makes it's way into the BigDecimal instance. That's why it's recommended to use a String to construct the value.

但是,当您使用浮点/双精度值来初始化 BigDecimal 时,同样的舍入错误会使其进入 BigDecimal 实例。这就是为什么建议使用 String 来构造值的原因。

回答by Jay Patel

I had a similar issue due to a rookie mistake which I wanted to share:

由于我想分享的菜鸟错误,我遇到了类似的问题:

BigDecimal bd = new BigDecimal(float); 

This was giving that extra precision I didn't want and setting it to String fixed it...

这提供了我不想要的额外精度并将其设置为 String 修复它......

However, I was doing this:

但是,我是这样做的:

BigDecimal bd = new BigDecimal(float);
bd.setScale(2, RoundingMode.HALF_UP);

Rookie Mistake. I should have done this.

菜鸟错误。我应该这样做。

bd = bd.setScale(2, RoundingMode.HALF_UP);