我有一个我正在修改的考试题目,问题是4分。
“在java中,我们可以将int赋给double或float”。这会丢失信息吗?为什么?
我已经说过,因为int通常具有固定的长度或大小 - 存储数据的精度是有限的,其中以浮点存储信息可能是无限的,基本上我们因此而丢失信息
现在我有点不清楚我是否在这里击中了正确的区域。我非常肯定它会失去精确度,但我无法完全理解为什么。我可以帮忙吗?
答案 0 :(得分:49)
在Java中,Integer使用32位来表示其值。
在Java中,FLOAT使用23位尾数,因此大于2 ^ 23的整数将截断其最低有效位。例如33554435(或0x200003)将被截断为大约33554432 +/- 4
在Java中,DOUBLE使用52位尾数,因此能够表示32位整数而不会丢失数据。
另请参阅维基百科上的“Floating Point”
答案 1 :(得分:23)
没有必要知道浮点数的内部布局。您所需要的只是鸽笼原则以及int
和float
大小相同的知识。
int
是32位类型,每个位模式代表一个不同的整数,因此有2 ^ 32 int
个值。float
是32位类型,因此它最多有2 ^ 32个不同的值。float
代表非整数,因此少于,而不是2 ^ 32 float
个值,代表整数。int
值将转换为相同的float
(=精度损失)。类似的推理可以与long
和double
一起使用。
答案 2 :(得分:18)
以下是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
的值不精确到九位有效数字。
答案 3 :(得分:13)
不,float
和double
也是固定长度的 - 他们只是以不同的方式使用它们的位。详细了解它们在the Floating-Poing Guide中的运作方式。
基本上,在将int
分配给double
时,您不会失去精确度,因为double
具有52位精度,足以容纳所有int
值。但float
只有23位精度,因此它不能准确表示大于约2 ^ 23的所有int
值。
答案 4 :(得分:4)
可能是我见过的最明确的解释: http://www.ibm.com/developerworks/java/library/j-math2/index.html ULP或最小精度单位定义任意两个浮点值之间的可用精度。随着这些值的增加,可用精度降低。 例如:介于1.0和2.0之间,有8,388,609个浮点数,1,000,000和1,000,001之间有17个。在10,000,000个ULP是1.0,所以高于这个值你很快会有多个整数值映射到每个可用的浮点数,因此精度会降低。
答案 5 :(得分:4)
你的直觉是正确的,将int
转换为float
时你可能会失去精确度。然而,它并不像大多数其他答案中那样简单。
在Java中,FLOAT使用23位尾数,因此大于2 ^ 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
因此,大于2 ^ 23的整数不会截断其最低有效位。
我找到的最佳解释是:
Java中的浮点数为32位,由下式表示:
符号*尾数* 2 ^指数
符号*(0至33_554_431)* 2 ^( - 125至+127)
资料来源:http://www.ibm.com/developerworks/java/library/j-math2/index.html
为什么这是一个问题?
它留下的印象是,你可以通过查看int的大小来确定从int到float 是否存在精度损失。
我特别看到了Java考试问题,其中一个被问到一个大的int是否会转换为一个没有丢失的浮点数。
此外,有时人们倾向于认为从int到float会有精度损失:
当int大于:1_234_567_890 不正确 (参见上面的反例)
当int大于:2指数23(等于:8_388_608)不正确
当int大于:2指数24(等于:16_777_216)不正确
<强>结论强>
从足够大的整数到浮点数的转换可能会失去精度
仅仅通过查看确定是否存在损失(即不试图深入到实际的浮动表示中)是不可能的。
答案 6 :(得分:1)
将int赋值给double或float可能会失去精度有两个原因:
答案 7 :(得分:0)
对于这些示例,我使用的是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;
}
使用这样的函数检查从long转换为float时的精度损失
static boolean checkPrecisionLossToFloat(long val)
{
if(val < 0)
{
val = -val;
}
// 8 + 32
return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 40;
}
对于这些函数中的每一个,返回true意味着将该整数值强制转换为浮点值将导致精度损失。
如果积分值超过24个有效位,则转换为float将失去精度。
如果积分值超过53个有效位,则转换为double将失去精度。
答案 8 :(得分:-1)
您可以将double分配为int而不丢失精度。