我对双精度有疑问。当将浮点值传递给双精度时,我会得到一些不同的结果。例如
float f= 54.23f;
double d1 = f;
System.out.println(d1);
输出为 54.22999954223633。有人可以解释这种行为背后的原因吗?是不是像 double 默认小数点后 14 位精度一样。
相同的值对于
float
和 double
的打印方式不同,因为 Java 规范要求根据需要打印尽可能多的数字,以将该值与相同类型中的相邻可表示值区分开(根据我的答案 here,并参阅 链接文档以获得更精确的定义)。
由于
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.23”(四舍五入到小数点后六位数字的结果,得到 54.230000,并删除尾随零)将将该值与 54.229995… 和 54.23… 区分开来。但是,double
的值分别为 54.22999954223632101957264239899814128875732421875 和 54.2299995422363352304273576010018587112 4267578125。为了区分该值,您需要“54.22999954223633”。试试这个:
System.out.println(f.doubleValue()); (当然需要先将其设为
Float) 如您所见,信息就在那里,只是四舍五入。 希望这有帮助
54.23f
输出
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
和
double
代表不同格式的数字。 因此,您一定会发现某些数字可以完美地以一种格式存储,但不能以另一种格式存储。您碰巧找到了一个可以正确适合
float
但不适合
float
的“双”。使用两个不同的格式化程序时也会出现此问题。
。
浮点数通常从左到右作为符号位、指数字段和有效数字(尾数)打包到计算机数据中。
这称为
。
浮点数不能精确地表示所有实数,并且浮点运算不能精确地表示真正的算术运算,这一事实导致了许多令人惊讶的情况。这与计算机通常表示数字的有限精度有关。
这不是问题。这就是 double 的工作原理。你不必处理它并关心它。 double 的精度就足够了。想一想,你的数字与预期结果之间的差异就在小数点后 14 位。
如果您需要任意好的精度,请使用
exactly
类。
java.math.BigDecimal
如有任何疑问,请告诉我。