java - 双倍乘以 100 然后转换为 long 给出了错误的值

标签 java floating-point numbers

我有以下代码:

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

O/P : 1730//预期:1731

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

O/P : 1732//预期:1733

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

O/P : 1732//预期:1732{如预期}

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

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

我已尝试谷歌但无法找到原因。如果问题微不足道,我很抱歉。

最佳答案

似乎没有一个答案涉及为什么 17.32表现不同。

1。为什么会发生

您在 17.3217.33 & 17.31 之间看到的行为差异是由于 IEEE-754 Rounding 规则造成的。

应用的舍入规则:从,The Java™ Virtual Machine Specification §2.8.1

The rounding operations of the Java virtual machine always use IEEE 754 round to nearest mode. Inexact results are rounded to the nearest representable value, with ties going to the value with a zero least-significant bit. This is the IEEE 754 default mode. The Java virtual machine does not give any means to change the floating-point rounding mode


2。您的情况:

双是:(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:(尾数比较)

Actual:   1.00010100111101011100001010001111010111000010100011110...
Internal: 1.0001010011110101110000101000111101011100001010001111

17.32:(尾数比较)

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

17.33:(尾数比较)

Actual:   1.00010101010001111010111000010100011110101110000101000...
Internal: 1.0001010101000111101011100001010001111010111000010100

4。转换回十进制:

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

( IEEE-754 Analysis Tool )

5。转换到长

编辑:正如@Jeppe Stig Nielsen 所说,在乘法步骤中还有一个因素在起作用。 FP 乘法 ( Reference ) 步骤的结果会向最近舍入。 这会改变结果是否符合预期,但原因仍然与上述完全相同。

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

缩小原始转换:The Java™ Language Specification §5.1.3

If the floating-point number is not an infinity, the floating-point value is rounded to an integer value V, rounding toward zero using IEEE 754 round-toward-zero mode

关于java - 双倍乘以 100 然后转换为 long 给出了错误的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13467849/

相关文章:

c - 打印链表的float元素显示不正确?

python - SymPy - 将数字视为符号

javascript - 检查输入字符串是否为正 int/float 数

java - 使用 Android 从 Microsoft Azure 插入和获取数据。出现错误

java - SpringMVC 错误

Scala 将两个整数相除并得到浮点结果

java - 重写 getColumnClass 方法后,jTable 仍然错误地对数字进行排序

java - 行人模拟 Java

java - 定时器在满足条件时给出错误

c++ - 浮点 C++ 编译器选项 |防止 a/b -> a* (1/b)