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

2022-01-17 00:00:00 floating-point numbers java

我有以下代码:

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}

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

I have tried to Google but unable to find reason.I am sorry if the question is trivial.

推荐答案

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

None of the answers seem to deal with why 17.32 acted different.

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

The difference in behaviour you see between 17.32 and 17.33 & 17.31 is due to IEEE-754 Rounding rules.

应用的舍入规则:来自 Java™ 虚拟机器规格 §2.8.1

Rounding rule applied: from, The Java™ Virtual Machine Specification §2.8.1

Java 虚拟机的舍入操作总是使用 IEEE754 舍入到最接近的模式.不精确的结果四舍五入到最接近的值可表示的值,与零值的关系最低有效位.这是 IEEE 754 默认模式.Java 虚拟机器没有给出任何改变浮点舍入的方法模式

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 位).四舍五入后的内部表示如下:


2. Your case:

Double is: (1 sign-bit + 11 exponent-bits + 52 fraction-bits = 64bits). Internal representation after rounding below:

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


3. Internal representation (Proof):

17.31: (Mantissa comparison)

Actual:   1.00010100111101011100001010001111010111000010100011110...
Internal: 1.0001010011110101110000101000111101011100001010001111

17.32:(尾数比较)

17.32: (Mantissa comparison)

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

17.33:(尾数比较)

17.33: (Mantissa comparison)

Actual:   1.00010101010001111010111000010100011110101110000101000...
Internal: 1.0001010101000111101011100001010001111010111000010100

<小时>

4.转换回十进制:

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

(IEEE-754 分析工具)

(IEEE-754 Analysis Tool)

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

There is a factor more at play at your multiplication step as @Jeppe Stig Nielsen said. The result of the FP multiplication (Reference) step does its own rounding-towards-nearest. This changes which results are as expected and which aren't, but the reason is still exactly the same as stated above.

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

Finally, due to the cast (long), truncation occurs, and leaves you with the results you see. (1730, 1732, 1732)

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

如果浮点数不是无穷大,则浮点数值四舍五入为整数值 V,使用四舍五入到零IEEE 754 向零舍入模式

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

相关文章