为什么以下语句在Java中会产生不同的输出?

huangapple go评论70阅读模式
英文:

Why do the following statements give different outputs in Java?

问题

对于一些 x 的值(x 是 long 类型),

x %= (1e9+7);

x %= 1_000_000_007;

会得到不同的答案。有什么想法可以解释这个现象吗?

此外,这种下划线格式(1_000_000_007)在各种编程语言中常见吗?除了提高可读性之外,还有什么优势吗?

英文:

For some values of x (x is of type long),

 x %= (1e9+7);

and

 x %= 1_000_000_007;

give different answers. Any idea why that could be?

Also, is this underscore format (1_000_000_007) common across languages? Are there advantages to it, apart from enhanced readability?

答案1

得分: 1

这是因为 1e9 是一个 double 字面值,而并非每个 long 值都可以被精确地表示为 double,因此在从 long 隐式转换为 double 时会丢失精度。

根据语言规范,当 xlong 类型的变量,而 ddouble 类型时,x %= d 相当于 x = (long) (x % d)。求余操作还会对操作数进行二进制数字提升,将 x 转换为 double 类型。

由于 double 是双精度的IEEE 754 浮点数,其尾数具有 53 位精度,不足以表示 long 值可能需要的全部 64 位精度。换句话说,doublelong 都使用 64 位,但有许多 double 值不是 long 值,因此也必然存在许多 long 值不是 double 值。因此,从 long 隐式转换为 double 可能会导致大于 2<sup>53</sup> 或小于 -2<sup>53</sup> 的值丢失精度。

顺便提一下,由于余数操作,由于精度丢失导致的错误可能最多达到 10<sup>9</sup> + 7 本身。例如,对于输入值 9_223_372_036_563_603_804L,错误值为 999_999_659

英文:

This is because 1e9 is a double literal, and not every long value can be exactly represented as a double, so there is a loss of precision due to an implicit conversion from long to double.

According to the language specification, x %= d is equivalent to x = (long) (x % d) when x is a variable of type long and d is of type double. The remainder operation also performs binary numeric prommotion on the operands, which converts x to type double.

Since double is a double-precision IEEE 754 floating-point number, it has 53 bits of precision for the mantissa, which is insufficient to represent all 64 bits of precision a long value may require. Put another way, both double and long use 64 bits, but there are many double values which are not long values, therefore there must also be many long values which are not double values. So the implicit conversion from long to double can result in a loss of precision for values greater than 2<sup>53</sup> or less than -2<sup>53</sup>.

By the way, because of the remainder operation, the error due to loss of precision could be up to 10<sup>9</sup> + 7 itself. For the input value 9_223_372_036_563_603_804L the error is 999_999_659, for example.

huangapple
  • 本文由 发表于 2020年4月7日 22:39:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/61082604.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定