我一直在试图找出原因,但是我没能找到。 有人可以帮助我吗?
看下面的例子。
float f = 125.32f;
System.out.println("value of f = " + f);
double d = (double) 125.32f;
System.out.println("value of d = " + d);
这是输出结果:
value of f = 125.32
value of d = 125.31999969482422
我一直在试图找出原因,但是我没能找到。 有人可以帮助我吗?
看下面的例子。
float f = 125.32f;
System.out.println("value of f = " + f);
double d = (double) 125.32f;
System.out.println("value of d = " + d);
这是输出结果:
value of f = 125.32
value of d = 125.31999969482422
当将一个float
转换为double
时,其值不会改变。由于需要区分double
值和其相邻值,因此显示数字存在差异,这是Java文档所要求的。这是toString
的文档,该文档通过多个链接与println
的文档相关联。
125.32f
的精确值为125.31999969482421875。两个相邻的float
值分别为125.3199920654296875和125.32000732421875。注意125.32更接近于125.31999969482421875而不是其任何一个相邻值。因此,通过显示“125.32”,Java已经显示了足够的数字,以便将十进制数转换回float
可以再现传递给println
的float
的值。
125.3199996948242的两个相邻的double
值分别为125.3199996948242045391452847979962825775146484375和125.3199996948242329608547152020037174224853515625。
观察到125.32更接近后面的那个邻居而不是原始值(125.31999969482421875)。因此,打印“125.32”并不能包含足够的数字来区分原始值。Java必须打印更多的数字以确保从显示的数字转换回double
会产生与传递给println
的double
值相同的值。
Resistance = scaleFactor/log(v1/v2);
。更有帮助的是说该值代表执行所有适当指定舍入的操作所得到的位组合,还是代表测量电阻?如果要定义应在一堆位上执行哪些操作,则前一种定义更有用,但如果要使用数字,则后者更有帮助。 - supercatfloat
转换为 double
时,不会有信息的丢失。每个 float
都可以准确地表示为一个 double
。System.out.println
输出的十进制表示并不是该数字的精确值。精确的十进制表示可能需要多达大约760个十进制数字。相反,System.out.println
输出的是刚好足够解析回原始 float
或 double
的小数位数。由于有更多的 double
,因此在打印一个 double
时,System.out.println
需要打印更多的数字才能使其表示变得明确无误。float
转换为 double
的。 “3.5E+38 的最佳浮点表示” 是 +inf
,而浮点数 +inf
转换为双精度浮点数 +inf
时不会失去精度(它们是相同的 inf
!)。如何解释这个无穷大是你的问题,而不是转换的问题。浮点值(这里是 +inf
)仅代表一个值(这里是无穷大)。您可以使用围绕 1.0f
和双精度浮点数 1.0
的 1-ulp 间隔进行相同的论证,但该论证同样不相关。被转换为 double
的是一个 float
,即单个值。 - Pascal Cuoqinf
。浮点值 inf
不是“包括 3.5E+38
的一系列值”,它是一个单独的值,即无穷大。在转换为 double
之前,将 3.5E38
转换为 +inf
的近似已经发生,并且不会阻止从 double
转换为精确值。 - Pascal Cuoqfloat2=float1/0.625f
,如果 float1
是 62.5f,那么 float2
的值表示最后一次操作的算术结果在 13421772.5/134217728 和 13421773.5/134217728 之间,并且将来使用 float2
的精确值为 13421773/134217728。如果 float1
是 3.4E38,则 float2
的值将指示... - supercatfloat2
将视为无穷大。如果想知道产生float2
的计算的算术结果是否可以明确地被认为比0.11或1.7E+308大,将每个比较的第二个操作数转换为float
会正确地报告它们不能。将float2
转换为double
会暗示它们可能会。 - supercatfloat
转换为double
是一种扩展转换,正如 JLS所规定的。扩展转换被定义为一个小集合到其超集的单射映射。因此,在从float
转换为double
后,所表示的数字不会改变。
在您的更新中,您添加了一个例子,旨在证明数字已经改变。然而,它只显示了由于转换为double
而获得的额外精度导致数字的字符串表示已经改变。请注意,您的第一个输出只是第二个输出的四舍五入。正如Double.toString
所指定的那样,
必须至少有一个数字来表示小数部分,并且除此之外还需要尽可能多的数字,但只有这么多数字才能唯一地区分类型
double
的相邻值与参数值。
由于类型double
中相邻的值比float
更接近,因此需要更多的数字来符合该规定。
float f = 125.32f;
System.out.println("value of f = " + f);
double d = Double.valueOf(String.valueOf(125.32f));
System.out.println("value of d = " + d);
value of f = 125.32
value of d = 125.32
System.out.println
在显示 float
或 double
值时会进行一些四舍五入,但两种情况下的四舍五入方法不同。BigDecimal
。float f = 125.32f;
System.out.println("value of f = " + new BigDecimal(f));
double d = (double) 125.32f;
System.out.println("value of d = " + new BigDecimal(d));
value of f = 125.31999969482421875
value of d = 125.31999969482421875
浮点数精度问题与编程语言无关,因此我将在解释中使用MATLAB。
之所以会出现差异是因为某些数字无法用固定位数精确表示。例如,取0.1
:
>> format hex
>> double(0.1)
ans =
3fb999999999999a
>> double(single(0.1))
ans =
3fb99999a0000000
0.1
转换为双精度浮点数时,误差会变大。如果直接使用双精度开始计算,结果将与其近似值不同。请注意保留 HTML 标签。>> double(single(0.1)) - double(0.1)
ans =
1.490116113833651e-09
float
会显示一个与打印从相同值转换而来的double
不同的数字(事实上它们具有相同的值,因为从float
到double
的转换并不改变值)。 - Eric Postpischil在Java中它不会工作,因为Java默认将实数作为双精度浮点数处理,如果我们声明一个没有float表示的浮点数值,例如123.45f,默认情况下它将被视为双精度浮点数,这将导致精度损失错误。
由于将数值转换为String
的方法的约定,数值的表示方式会发生变化,分别是java.lang.Float#toString(float)
和java.lang.Double#toString(double)
,而实际值保持不变。在这两个方法的Javadoc中有一个共同的部分,详细说明了数值的String
表示要求:
至少需要一个数字来表示小数部分,并且除此之外还需要足够多的数字,但只能是足够多的数字,以便能够唯一区分参数值与相邻值
为了说明这两种类型的值的重要部分的相似性,可以运行以下代码片段:
package com.my.sandbox.numbers;
public class FloatToDoubleConversion {
public static void main(String[] args) {
float f = 125.32f;
floatToBits(f);
double d = (double) f;
doubleToBits(d);
}
private static void floatToBits(float floatValue) {
System.out.println();
System.out.println("Float.");
System.out.println("String representation of float: " + floatValue);
int bits = Float.floatToIntBits(floatValue);
int sign = bits >>> 31;
int exponent = (bits >>> 23 & ((1 << 8) - 1)) - ((1 << 7) - 1);
int mantissa = bits & ((1 << 23) - 1);
System.out.println("Bytes: " + Long.toBinaryString(Float.floatToIntBits(floatValue)));
System.out.println("Sign: " + Long.toBinaryString(sign));
System.out.println("Exponent: " + Long.toBinaryString(exponent));
System.out.println("Mantissa: " + Long.toBinaryString(mantissa));
System.out.println("Back from parts: " + Float.intBitsToFloat((sign << 31) | (exponent + ((1 << 7) - 1)) << 23 | mantissa));
System.out.println(10D);
}
private static void doubleToBits(double doubleValue) {
System.out.println();
System.out.println("Double.");
System.out.println("String representation of double: " + doubleValue);
long bits = Double.doubleToLongBits(doubleValue);
long sign = bits >>> 63;
long exponent = (bits >>> 52 & ((1 << 11) - 1)) - ((1 << 10) - 1);
long mantissa = bits & ((1L << 52) - 1);
System.out.println("Bytes: " + Long.toBinaryString(Double.doubleToLongBits(doubleValue)));
System.out.println("Sign: " + Long.toBinaryString(sign));
System.out.println("Exponent: " + Long.toBinaryString(exponent));
System.out.println("Mantissa: " + Long.toBinaryString(mantissa));
System.out.println("Back from parts: " + Double.longBitsToDouble((sign << 63) | (exponent + ((1 << 10) - 1)) << 52 | mantissa));
}
}
Float.
String representation of float: 125.32
Bytes: 1000010111110101010001111010111
Sign: 0
Exponent: 110
Mantissa: 11110101010001111010111
Back from parts: 125.32
Double.
String representation of double: 125.31999969482422
Bytes: 100000001011111010101000111101011100000000000000000000000000000
Sign: 0
Exponent: 110
Mantissa: 1111010101000111101011100000000000000000000000000000
Back from parts: 125.31999969482422
通过这种方式,您可以看到值的符号、指数相同,而它的尾数被扩展并保留了其重要部分(11110101010001111010111
)完全相同。
两者都是微软所称的“近似数字数据类型”。
有一个原因。float的精度为7位数字,double为15位。但我已经看到许多次8.0 - 1.0 - 6.999999999。这是因为它们不能保证完全表示小数。
如果您需要绝对不变的精度,请选择decimal或整数类型。
float
值(比如x=1.0和y=10.0),并计算float z=x/y;
,那么程序员更可能认为z
保存了输入分数的不完美表示,而不是13421773/134217728分数的精确表示。 - supercat