英文:
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
时会丢失精度。
根据语言规范,当 x
是 long
类型的变量,而 d
是 double
类型时,x %= d
相当于 x = (long) (x % d)
。求余操作还会对操作数进行二进制数字提升,将 x
转换为 double
类型。
由于 double
是双精度的IEEE 754 浮点数,其尾数具有 53 位精度,不足以表示 long
值可能需要的全部 64 位精度。换句话说,double
和 long
都使用 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论