简体   繁体   English

java-在控制台中输出时的浮点精度

[英]java - float precision when output in console

float x = 0.98123452f;
System.out.println(x); //it prints out 0.9812345

float x = 0.98123453f;
System.out.println(x); //it prints out 0.98123455

I have no idea why the second one's output is 0.98123455 instead of 0.9812345. 我不知道为什么第二个输出是0.98123455而不是0.9812345。 Isn't the precision of float is 7 decimal digits? 浮点数的精度不是7个十进制数字吗?

To see the exact value of your float, you can use a BigDecimal: 要查看浮点数的确切值,可以使用BigDecimal:

 
 
 
  
  float x = 0.98123452f; System.out.println(new BigDecimal(x));
 
  

which outputs: 0.981234490871429443359375 输出: 0.981234490871429443359375

So technically, this float: 因此,从技术上讲,该浮动:

 
 
 
  
  float x = 0.981234490871429443359375f; System.out.println(new BigDecimal(x)); //prints 0.981234490871429443359375
 
  

has 24 digits precision (it was obviously cherry-picked)... 具有24位精度(显然是挑剔的)...

Forget what is above: BigDecimal only has a double constructor so there was a cast to double and the logic above is flawed. 忘记上面的内容:BigDecimal只有一个double构造函数,因此进行了强制转换为double,并且上面的逻辑存在缺陷。

Bottom line: not all numbers can be represented as a float and the gap between one float and the next one varies depending on the magnitude of the number. 底线:并非所有数字都可以表示为浮点数,一个浮点数与下一个浮点数之间的距离取决于数字的大小而变化。

The IEEE 754 float representation of IEEE 754的浮点表示形式

0.98123453 

is 32 bits of (sign, exp, mantissa): 是32位(符号,exp,尾数):

0 01111110 11110110011001000110000

which is: 这是:

0.9812345504760742

in double precision, and cast back to float decimal representation: 以双精度,然后转换回浮点十进制表示形式:

 0.98123455

The number of bits allocated to a single precision (float) is 32, and 64 bits for double precision. 分配给单精度(浮点数)的位数为32,而双精度则为64位。 Further note that BigDecimal that is frequently suggested will store your number as a string, and not in IEEE754 format. 还要注意,经常建议使用BigDecimal ,它将您的数字存储为字符串,而不是IEEE754格式。 It will do a conversion when it needs to act on the number, and while it has a better precision, it is awfully slow. 当需要对数字进行运算时,它将进行转换,并且虽然精度更高,但速度非常慢。

EDIT. 编辑。 To clarify why it prints 0.98123455, we need to observe that it is the closest single precision representation of the number 0.98123453: 为了阐明为什么打印0.98123455,我们需要观察它是数字0.98123453的最接近的单精度表示形式:

00111111011110110011001000101111 = 0.9812345  (sp) = 0.9812344908714294 (dp)
00111111011110110011001000110000 = 0.98123455 (sp) = 0.9812345504760742 (dp)
00111111011110110011001000110001 = 0.9812346  (sp) = 0.981234610080719  (dp)

sp = single precision, dp = double precision sp =单精度,dp =双精度

The listing is for the [-1,+1] binary range around the number, and you can see that 0.98123453 is closest to the 10000 suffix of the mantissa, while 0.98123452 is closest to the 01111 suffix. 该清单是针对数字附近的[-1,+ 1]二进制范围的,您可以看到0.98123453最接近尾数的10000后缀,而0.98123452最接近后缀01111

isn't the precision of float is 7 decimal digits? 浮点数的精度不是7个十进制数字吗?

No. It is 23 binary digits. 否。它是23位二进制数字。 The minimum number of decimal digits that can be represented in 23 bits is therefore 6. This is not a mere 'guarantee' as stated in other answers here, it is a mathematical tautology arising from log10(2^23) = 6.92369. 因此,可以用23位表示的十进制数字的最小数目为6。这不仅仅是在此处的其他答案中所述的“保证”,它是由log10(2 ^ 23)= 6.92369引起的数学重言式。

The default output format for floating-point in Java is to print just enough digits so that conversion back to the floating-point type produces the original value. Java中浮点数的默认输出格式是仅打印足够的数字,以便转换回浮点类型时会产生原始值。

What happens in detail in your code is: 您的代码中发生的详细信息是:

  • The source text 0.98123452f is converted to the float value 0.981234490871429443359375. 源文本0.98123452f转换为float值0.981234490871429443359375。
  • This is printed as “0.9812345” because that is just enough digits. 这被打印为“ 0.9812345”,因为这仅仅是足够的数字。 The nearest float value to 0.9812345 is 0.981234490871429443359375. 最接近0.9812345的float值是0.981234490871429443359375。 However, converting “0.981234” to float would produce 0.981234014034271240234375, so the “5” is needed. 但是,将“ 0.981234”转换为float将产生0.981234014034271240234375,因此需要“ 5”。
  • The source text 0.98123453f is converted to the float value 0.98123455047607421875. 源文本0.98123453f转换为float值0.98123455047607421875。
  • This is printed as “0.98123455” because that is just enough digits. 这被打印为“ 0.98123455”,因为这已经足够了。

An interesting consequence of this is that, if you assign a float value to a double object and then print the double value, it will often display more digits than printing the float value, even though the values are exactly the same. 有趣的结果是,如果将float值分配给double对象,然后打印该double值,则即使打印的值完全相同,也通常会比打印float值显示更多的数字。 Because the double format is finer (more precise) than the float format, there may be many double values between the value printed for float (eg 0.9812345) and the actual value (0.981234490871429443359375). 因为double格式比float格式更好(更精确),所以在为float打印的值(例如0.9812345)和实际值(0.981234490871429443359375)之间可能会有很多double值。 Therefore, more digits are needed to distinguish the value. 因此,需要更多的数字来区分该值。

不, float只有六位数的十进制精度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM