当前位置: 首页 > 面试题库 >

将double乘以100,然后转换为long表示错误的值

海保臣
2023-03-14
问题内容

我有以下代码:

Double i=17.31;
long j=(long) (i*100);
System.out.println(j);

O / P: 1730 //Expected:1731

Double i=17.33;
long j=(long) (i*100);
System.out.println(j);

O / P: 1732 //Expected:1733

Double i=17.32;
long j=(long) (i*100);
System.out.println(j);

O / P: 1732 //Expected:1732{As expected}

Double i=15.33;
long j=(long) (i*100);
System.out.println(j);

O / P: 1533 //Expected:1533{as Expected}

我已经尝试过使用Google,但是找不到原因。如果问题很简单,我们感到抱歉。


问题答案:

答案似乎都没有涉及 为什么 17.32采取不同的行动。

1.为什么发生

您看到的17.32和之间的行为差​​异17.33 & 17.31是由于IEEE-754 舍入 规则引起的。

应用的舍入规则:摘自Java™虚拟机规范
§2.8.1

Java虚拟机的舍入操作始终使用IEEE 754舍入到最近模式。不精确的结果四舍五入到最接近的可表示值,并用最低有效位为零的值舍入。这是IEEE
754的默认模式。Java虚拟机未提供任何方法来更改浮点舍入模式

2.您的情况:

Double是 :(1个符号位+ 11个指数位+ 52个小数位= 64位)。 四舍五入后的内部表示

             1 [63]      11 [62-52]           52 [51-00]
              Sign        Exponent             Fraction

17.31 -->    0 (+)       10000000011 (+4)     1.0001010011110101110000101000111101011100001010001111
17.32 -->    0 (+)       10000000011 (+4)     1.0001010100011110101110000101000111101011100001010010 //rounded up
17.33 -->    0 (+)       10000000011 (+4)     1.0001010101000111101011100001010001111010111000010100

3.内部表示(证明):

17.31:(Mantissa比较)

Actual:   1.00010100111101011100001010001111010111000010100011110...
Internal: 1.0001010011110101110000101000111101011100001010001111

17.32:(Mantissa比较)

Actual:   1.00010101000111101011100001010001111010111000010100011... 
Internal: 1.0001010100011110101110000101000111101011100001010010    //round-up!

17.33:(Mantissa比较)

Actual:   1.00010101010001111010111000010100011110101110000101000...
Internal: 1.0001010101000111101011100001010001111010111000010100

4.转换为小数:

17.31 ->  17.309999999999998721023075631819665431976318359375...
17.32 ->  17.32000000000000028421709430404007434844970703125... //(was rounded up)
17.33 ->  17.3299999999999982946974341757595539093017578125...

IEEE-754分析工具

5.转换为长

编辑: 正如@Jeppe Stig Nielsen所说,在您的乘法步骤中还有更多因素在起作用。 FP 乘法(
参考
)步骤的结果将其自身舍入为最接近的值。这种变化会产生预期的结果,而不会产生预期的结果,但是原因仍然与上述完全相同。

最后,由于强制转换(long),会发生截断,并使您看到的结果保留下来。(1730, 1732, 1732)

缩小原始转换:Java™语言规范
§5.1.3

如果浮点数不是无穷大,则将浮点值舍入为整数值V,并使用IEEE 754舍入为零模式舍入为零。



 类似资料:
  • 考虑此代码段: 在我的机器上运行这个会打印两个转换的。但是和只能是吗? 据我所知,这是一个扩展的原语转换,规范中说: 拓宽的基元转换不会丢失有关数值的整体大小的信息。 以及 将int或long值加宽为float或将long值加宽为double可能会导致精度损失 据我所知,上述规范意味着将始终成为,但可以转换为其他内容(例如或类似内容)。我的规格解释正确吗?

  • 问题内容: 我已经寻找了40分钟以上,试图在此站点上找到可能与我的问题无关的答案。 我很沮丧。我正在尝试将程序转换为GUI。我正在使用Textpad,它告诉我何时编译该变量已在main方法中定义。然后,当转换为int或double时,它告诉我找不到符号,并指向我要转换的变量。然后在计算时,它告诉我二进制运算符’*’的操作数类型错误。 问题答案: 做不到 替换为,因为这是您在使用时要解析的变量!(也

  • 问题内容: 我正在实现一个接口,该接口的功能类似于可以包含某种对象的表的功能。该接口指定以下功能: 在我的实现中,我感到很困惑的是,我将表数据存储在2D 数组()中。当我需要返回值时,我想执行以下操作(假定只在包含double的列上调用,因此将没有): 但是- Java不允许强制转换为。将其强制转换为可以,因为它是一个对象,而不是基元,但是我的接口指定数据将以形式返回。 所以我有两个问题: 有什么

  • 问题内容: 如何在Java中将值转换为值? 问题答案: 或如果您不必担心null: 在这两种情况下,您都可能会遇到溢出问题(因为Long可以比Integer存储更大的范围)。 Java 8有一个辅助方法来检查溢出(在这种情况下,您会得到一个异常):

  • 问题内容: 这可能是一个简单的,总机问题,但我的第一次尝试令人惊讶地完全失败了。我想获取一组原始的long并将其转换成一个列表,我试图这样做: 什么是正确的方法? 问题答案: 我发现使用apache commons lang ArrayUtils(JavaDoc,Maven依赖项)很方便 它还具有反向API 编辑:更新以提供完整的转换为列表,如注释和其他修复建议。

  • 问题内容: 点后如何将double转换为2? 例如: 我需要那个(在Java for Android中) 提前致谢 问题答案: x = Math.floor(x * 100) / 100;