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

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) 是否跨语言通用?除了增强可读性之外,它还有其他优势吗?

这是因为1e9是一个double字面量,并不是每个long值都可以精确表示为double,所以会损失精度由于从 longdouble.

的隐式转换

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 在操作数上,将 x 转换为类型 double.

由于double是双精度IEEE 754 floating-point number,它的尾数有53位精度,不足以表示所有64位精度long值可能要求。换句话说,doublelong都使用64位,但是有很多double值不是long值,因此也一定有很多long 值不是 double 值。因此,对于大于 253 或小于 -253 的值,从 longdouble 的隐式转换会导致精度损失.

顺便说一下,由于取余运算,由于精度损失导致的误差可能高达 109 + 7 本身。例如,对于输入值 9_223_372_036_563_603_804L,错误是 999_999_659