我正在复习一道考试题,这道题的分值为4分。
"在Java中,我们可以将int赋值给double或float。" 这样做是否会丢失信息?为什么?
我这样写是因为int通常是固定长度或大小的 - 存储数据的精度是有限的,而在浮点数中存储信息可以是无限的,基本上是由于这个原因我们会丢失信息。
现在我对自己是否到达了正确的研究领域有些疑惑。 我很确定它会失去精度,但我确切地说不清楚原因。 能否请您提供一些帮助呢?
我正在复习一道考试题,这道题的分值为4分。
"在Java中,我们可以将int赋值给double或float。" 这样做是否会丢失信息?为什么?
我这样写是因为int通常是固定长度或大小的 - 存储数据的精度是有限的,而在浮点数中存储信息可以是无限的,基本上是由于这个原因我们会丢失信息。
现在我对自己是否到达了正确的研究领域有些疑惑。 我很确定它会失去精度,但我确切地说不清楚原因。 能否请您提供一些帮助呢?
在Java中,Integer使用32位来表示其值。
在Java中,FLOAT使用23位的尾数,因此大于2 ^ 23的整数将被截断其最不重要的位。例如,33554435(或0x200003)将被截断为约33554432 +/- 4。
在Java中,DOUBLE使用52位的尾数,因此能够表示32位整数而不会丢失数据。
另请参见维基百科上的“浮点数”
了解浮点数的内部布局并不是必要的。你只需要掌握抽屉原理和int
和float
类型具有相同的大小。
int
是32位类型,其每个比特模式表示一个不同的整数,因此有2^32种int
值。float
是32位类型,因此它最多有2^32个不同的值。float
表示非整数,因此表示整数的float
值少于 2^32。int
值将被转换为相同的float
(即丢失精度)。类似的推理可以用于long
和double
。
以下是JLS关于该问题的非技术性讨论。
原始类型上的19种特定转换称为扩展原始类型转换:
int
转long
、float
或double
- (其他省略)
将
int
或long
值转换为float
,或将long
值转换为double
,可能会导致精度损失 -- 即结果可能会失去一些最低有效位的值。在这种情况下,使用IEEE 754四舍五入到最近模式对整数值进行正确舍入后,所得到的浮点数值将是正确的。尽管可能会发生精度损失,但原始类型之间的扩展转换永远不会导致运行时异常。
以下是一个会丢失精度的扩展转换示例:
class Test { public static void main(String[] args) { int big = 1234567890; float approx = big; System.out.println(big - (int)approx); } }
输出以下内容:
-46
因此表明在从类型为
int
的值转换为类型为float
的值时丢失了信息,因为类型为float
的值不精确到九个有效数字。
int
值,更精确的说法是连续可表示整数的范围正好从-2^24到+2^24。这些值以及它们之间的所有值都可以用float
表示;而超出该范围的最接近整数则不能。 - supercatint
转换为float
时可能会失去精度。但是,这并不像大多数其他答案中所述那样简单。
不是真的。在Java中,FLOAT使用23位尾数,因此大于2^23的整数将截断其最低有效位。(摘自本页上的帖子)
int i = 33_554_430 * 64; // is greater than 2^23 (and also greater than 2^24); i = 2_147_483_520
float f = i;
System.out.println("result: " + (i - (int) f)); // Prints: result: 0
System.out.println("with i:" + i + ", f:" + f);//Prints: with i:2_147_483_520, f:2.14748352E9
将int赋值给double或float可能会丢失精度,原因有两个:
对于这些示例,我使用Java。
使用类似以下的函数来检查从int到float转换时是否存在精度损失
static boolean checkPrecisionLossToFloat(int val)
{
if(val < 0)
{
val = -val;
}
// 8 is the bit-width of the exponent for single-precision
return Integer.numberOfLeadingZeros(val) + Integer.numberOfTrailingZeros(val) < 8;
}
static boolean checkPrecisionLossToDouble(long val)
{
if(val < 0)
{
val = -val;
}
// 11 is the bit-width for the exponent in double-precision
return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 11;
}
static boolean checkPrecisionLossToFloat(long val)
{
if(val < 0)
{
val = -val;
}
// 8 + 32
return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 40;
}
你可以将double赋值给int而不会失去精度。
float
和double
并没有无限精度。如果是这样的话,它们就会成为神奇的东西,在有限的内存空间中存储无限量的信息。 - Jesperint
存储到之前没有存储任何有用信息的float
中,然后丢弃或覆盖int
可能会丢失信息,但是造成信息丢失的是丢弃或覆盖int
的行为,而不是存储float
。相反,覆盖任何类型的任何变量,该变量保存了唯一的有用信息副本,即使将变量设置为存储另一个变量中信息的完美副本,也可能导致信息丢失。 - supercat