今天演示 Java 显式类型转换时遇到了一个奇怪的怪癖,并且想知道为什么会发生这种情况。
如果我将 double 转换为 int,并且我的数字是 0.9 到 16 精度,它将向上舍入。 (请参阅代码中的注释)如果我将其设为 15 精度,则会向下舍入。
同样,如果我将数字设为 0.8...它仍会向下舍入。
double a = 5.9999999999999999;// 16 precision rounds to 6
double a1 = 5.8888888888888888; // 16 precision rounds to 5
double b = 5.999999999999999;// 15 precision rounds to 5
double c = 5.111111111111111111111111111111111111111; //rounds to 5
int cast = (int)a;
for (int i = 0 ; i < 1000000 ; i++){
System.out.print(cast);
}
最初以为我溢出了int,但事实似乎并非如此。
有什么想法吗?
这与投射到
int
无关。
如果打印
a
的值:
double a = 5.9999999999999999;
System.out.println(a);
打印出
6.0
。
这是因为 double 的精度有限,无法准确表示字面值。
根据 JLS 第 5.1.3 节,涉及从浮点类型到整型类型的缩小原始转换的转换将舍入为零:
浮点数到整型 T 的缩小转换需要两个步骤:
- 在第一步中,如果 T 是 long,则将浮点数转换为 long;如果 T 是 byte、short、char 或 int,则将浮点数转换为 int,如下所示:
- 如果浮点数为 NaN(第 4.2.3 节),则第一步转换的结果为 int 或 long 0。
- 否则,如果浮点数不是无穷大,则使用向零舍入策略(第 4.2.4 节)将浮点值舍入为整数值 V。
那么为什么
double a = 5.9999999999999999;
看起来四舍五入呢? double
文字必须首先转换为 double
值。 JLS (3.10.2): 的浮点文字部分对此进行了介绍
包 java.lang 的 Float 类和 Double 类的方法 valueOf 描述了从浮点数的 Unicode 字符串表示形式到内部 IEEE 754 二进制浮点表示形式的正确输入转换的详细信息。
valueOf
找Double
:
(粗体强调我的)[字符串值]被视为代表通常的“计算机科学计数法”中的精确十进制值或精确的十六进制值;然后,这个精确的数值在概念上被转换为“无限精确”的二进制值,然后通过 IEEE 754 浮点算术的常用“舍入到最近规则”舍入到类型“
”,其中包括保留零值。double
小数点后有 16 位精度(包括
5
在内有 17 位),您正在突破
double
文字的精度极限。此时,5.9999999999999999
比下一个较低的 6
值更接近 double
。因此,显示 6 是因为您的浮点文字被四舍五入为 6.0
before 为
double
,而 int
为 6.0
转换为 int
是 6你看到印刷的。您拥有的其他值不会像 6.0
文字那样一直四舍五入到 double
,因此转换为
int
会使其一直下降到 5。