2013-03-21 151 views
3

我有问题关于双精度。当float值传入double时,我得到一些不同的结果。对于例如双精度浮点值传递双精度时

float f= 54.23f; 
double d1 = f; 
System.out.println(d1); 

输出是54.22999954223633。有人能解释这种行为背后的原因吗?它是否像双精度值到十进制精度的十四个位置?

回答

-1

doublefloat代表不同格式的数字。

正因为如此,你一定会发现某些数字完全以一种格式存储,而不是另一种格式。你碰巧找到了一个正确匹配float,但不适合exactly的“double”。

当两个不同的格式化程序被使用时,这个问题也会出现。

+4

'double'使用与'float'相同的基本格式,它只是使用更多的位。每个“float”值都应该可以用“double”来表示。 – 2013-03-21 13:53:58

+0

@JoachimSauer:对于每个'float',都有一个具有相同标称值的'double',但浮点数的含义超出了标称值。考虑下面的问题:“将一个3.0cm的钉子固定在一个3.002cm的洞里?”和“3.000厘米的钉子会套在3.002厘米的洞里吗?”两个钉子的标称尺寸完全相同,但是后者钉子被指定为合适的,而前者不是(即使它是3.004厘米,仍然可以被描述为3.0厘米钉子)。没有与任何“浮动”值相同的“含义”的“双”值;对于两个值来说,没有'double'更接近。 – supercat 2013-07-25 23:38:45

0

这是因为float隐藏了额外的小数,double显示它们。双数将精确地表示实际数字并显示更多数字。

尝试这种情况:

的System.out.println(f.doubleValue()); (需要使它成为Float第一个课程)

所以,你可以看到,信息在那里,它只是圆形。 希望这有助于

+0

很可能'f.doubleValue()'被实现为'new Double(f)'。 – OldCurmudgeon 2013-03-21 13:49:30

+0

@OldCurmudgeon,它是演员。 'return(double)value;' – jn1kk 2013-03-21 13:51:01

+1

这很接近,但并不完整。打印“双”并不总是显示更精确;有时它会显示与在“float”中打印相同值相同的结果。实际的规则是打印的数字必须是打印传递的值是最接近数字值的类型的值(带有关于关系的一些附加规则)。这通常会导致'double'显示的数字比'float'更多,但并非总是如此。 – 2013-03-21 15:05:26

0

这是由于Internal Representation
浮点数通常从左到右依次包含在计算机数据中,作为符号位,指数字段和有效位数(尾数)。

这被称为Accuracy Problems
浮点数不能精确表示所有实数并且浮点运算不能精确表示真正的算术运算的事实会导致很多令人惊讶的情况。这与计算机通常表示数字的有限精度有关。

这不是问题。这是双重作品。你不必处理它并关心它。双精度就足够了。想想,你的数字和预期结果之间的差异是在小数点后的14位。

如果您需要任意高精度,请使用java.math.BigDecimal类。

或者如果你还想使用双。这样做:

double d = 5.5451521841; 
NumberFormat nf = new DecimalFormat("##.###"); 
System.out.println(nf.format(d)); 

如果有任何疑问,请让我知道。

+0

我不相信这个问题是关于为什么'54.23f'没有54.23的值,但是为什么将它打印为'double'显示的数字比打印为'float'的数字要多,即使打印的是相同的值。 – 2013-03-21 15:06:09

0

其实这只是关于不同的视觉表示或将float/double转换为String。让我们来看看内部二进制表示

float f = 0.23f; 
    double d = f; 
    System.out.println(Integer.toBinaryString(Float.floatToIntBits(f))); 
    System.out.println(Long.toBinaryString(Double.doubleToLongBits(d))); 

输出

111110011010111000010100011111 
11111111001101011100001010001111100000000000000000000000000000 

这意味着f转化为d1没有任何失真,显著数字是相同的

+0

这是如何回答这个问题的? – 2013-03-21 15:06:37

+0

Double.toString以不同的方式转换0.23f,而实际值相同 – 2013-03-21 15:10:29

+0

这并不能解释原因。 **相同值**的打印方式有何不同? – 2013-03-21 15:11:07

6

相同的值被打印不同对于floatdouble,因为Java规范要求根据需要打印尽可能多的数字以区分相同值中的值和相邻的可表示值键入(根据我的回答here,并在定义中查看linked documentation以获得更高精度)。

由于float只有较少的位来表示值,因此值越小,它们的间隔就越大,并且不需要很多数字来区分它们。将值放入double并打印出来时,Java规则要求打印更多数字,以便将值与附近的double值区分开来。函数println不知道该值最初来自float,并且没有包含尽可能多的信息以适应double

54.23f正好是54.229999542236328125(十六进制,0x1.b1d70ap + 5)。刚刚低于此值的float值为54.2299957275390625(0x1.b1d708p + 5)和54.23000335693359375(0x1.b1d70cp + 5)。正如你所看到的,打印“54.229999”将区分54.229995 ...和54.23 ...的值。然而,正好低于54.23fdouble值是54.1957264239899814128875732421875和54.22999954223633523042735760100185871124267578125。要区分这个值,你需要“54.22999954223633”。

+0

我真的不喜欢将隐式'float'转换为'double'转换的一个原因是,即使从位级的角度来看,像0x1一样。B1D708A + 5是二次幂分数的完美表示,浮点变量更典型地用作不是二次幂次幂数的不完美表示。如果我知道最接近某个数字的'float'是0x1.B1D708A + 5,这意味着该数字在一定的范围内,但应该被认为与该范围内的其他值无法区分。将其转换为“double”... – supercat 2013-09-04 07:23:12

+0

...将虚假地假设并暗示该变量旨在表示的数字非常接近“float”可以表示的数字范围的中心,尽管在实践中存在这个假设可能没有可信的基础。关于16777217f和16777216.0001作为等级排列,恕我直言不如将前一个值排在较低位置(如果比较运算符将两个操作数隐式转换为“double”,会发生什么情况)。 – supercat 2013-09-04 07:28:34

+0

这是一种不正当的用法。 'float'和'double'都不能携带关于它周围区间的任何信息。它代表一个单一的数字。有些人认为它代表了一个间隔,比如说相邻值的中点。但是,只有执行了单个操作(例如从十进制到二进制浮点的转换),情况才会成立。经过一次以上的操作后,错误可能会更大,并且它不会如何增长。因此,如果要表示区间信息,则它必须在单独的数据中进行...... – 2013-09-05 15:04:47