[英]What's the right way to parseFloat in Java
I notice some issues with the Java float precision 我注意到Java浮点精度的一些问题
Float.parseFloat("0.0065") - 0.001 // 0.0055000000134110451
new Float("0.027") - 0.001 // 0.02600000000700354575
Float.valueOf("0.074") - 0.001 // 0.07399999999999999999
I not only have a problem with Float
but also with Double
. 我不仅有Float
的问题,还有Double
。
Can someone explain what is happening behind the scenes, and how can we get an accurate number? 有人可以解释幕后发生的事情,我们怎样才能获得准确的数字? What would be the right way to handle this when dealing with these issues? 在处理这些问题时,处理此问题的正确方法是什么?
The problem is simply that float
has finite precision; 问题在于float
具有有限的精度; it cannot represent 0.0065
exactly. 它不能完全代表0.0065
。 (The same is true of double
, of course: it has greater precision, but still finite.) (当然, double
也是如此:它具有更高的精度,但仍然是有限的。)
A further problem, which makes the above problem more obvious, is that 0.001
is a double
rather than a float
, so your float
is getting promoted to a double
to perform the subtraction, and of course at that point the system has no way to recover the missing precision that a double
could have represented to begin with. 使上述问题更加明显的另一个问题是0.001
是一个double
而不是float
,所以你的float
被提升为double
来执行减法,当然在这一点上系统无法恢复double
可能代表的缺失精度。 To address that, you would write: 为了解决这个问题,你会写:
float f = Float.parseFloat("0.0065") - 0.001f;
using 0.001f
instead of 0.001
. 使用0.001f
而不是0.001
。
See What Every Computer Scientist Should Know About Floating-Point Arithmetic . 看看每个计算机科学家应该知道的关于浮点运算的内容 。 Your results look correct to me. 你的结果对我来说是正确的。
If you don't like how floating-point numbers work, try something like BigDecimal instead. 如果您不喜欢浮点数的工作方式,请尝试使用类似BigDecimal的方法 。
You're getting the right results. 你得到了正确的结果。 There is no such float
as 0.027 exactly, nor is there such a double
. 没有像0.027那样的float
,也没有这样的double
。 You will always get these errors if you use float
or double
. 如果使用float
或double
则总会出现这些错误。
float
and double
are stored as binary fractions : something like 1/2 + 1/4 + 1/16... You can't get all decimal values to be stored exactly as finite-precision binary fractions. float
和double
存储为二进制分数 :类似于1/2 + 1/4 + 1/16 ......您无法将所有十进制值精确地存储为有限精度二进制分数。 It's just not mathematically possible. 这在数学上是不可能的。
The only alternative is to use BigDecimal
, which you can use to get exact decimal values. 唯一的选择是使用BigDecimal
,您可以使用它来获取精确的十进制值。
From the Java Tutorials page on Primitive Data Types : 从“ 原始数据类型的Java教程”页面 :
A floating-point literal is of type float if it ends with the letter
F
orf
; 如果浮点字面值以字母F
或f
结尾,则浮点字面值为float类型; otherwise its type is double and it can optionally end with the letterD
ord
. 否则它的类型是双倍的,它可以选择以字母D
或d
结尾。
So I think your literals ( 0.001
) are doubles and you're subtracting doubles from floats. 所以我认为你的文字( 0.001
)是双打的,你从浮动中减去双打。
Try this instead: 试试这个:
System.out.println((0.0065F - 0.001D)); // 0.005500000134110451
System.out.println((0.0065F - 0.001F)); // 0.0055
... and you'll get: ......你会得到:
0.005500000134110451
0.0055
So add F
suffixes to your literals and you should get better results: 因此,在文字中添加F
后缀,您应该得到更好的结果:
Float.parseFloat("0.0065") - 0.001F
new Float("0.027") - 0.001F
Float.valueOf("0.074") - 0.001F
Long story short if you require arbitrary precision use BigDecimal not float or double. 如果您需要任意精度,请使用BigDecimal,不要浮动或加倍。 You will see all sorts of rounding issues of this nature using float. 你会看到使用float这种性质的各种舍入问题。
As an aside be very careful not to use the float/double constructor of BigDecimal because it will have the same issue. 另外要小心不要使用BigDecimal的float / double构造函数,因为它会有同样的问题。 Use the String constructor instead. 请改用String构造函数。
Floating point cannot accurately represent decimal numbers. 浮点不能准确表示十进制数。 If you need an accurate representation of a number in Java, you should use the java.math.BigDecimal class: 如果您需要在Java中准确表示数字,则应使用java.math.BigDecimal类:
BigDecimal d = new BigDecimal("0.0065");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.