在实施 Mersenne Twister 时,这个数字应该减去 1 吗?

问题描述

我在网上找到了 this snippet 以及 this Stackoverflow 帖子,后者将其转换为 TypeScript 类。

我基本上是逐字复制粘贴的(因为我没有资格修改这种加密代码),但我注意到 VS Code 在最后一个函数中有一点下划线:

/**
 * generates a random number on [0,1) with 53-bit resolution
 */
nextNumber53(): number {
  let a = this._nextInt32() >>> 5;
  let b = this._nextInt32() >>> 6;
  
  return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}

特别是 9007199254740992.0

VS Code 说 Numeric literals with absolute values equal to 2^53 or greater are too large to be represented accurately as integers.ts(80008)

我注意到,如果我将该数字减去 1 并改为 9007199254740991.0,那么警告就会消失。但如果这确实是一个显着差异,我不一定要修改代码并破坏它。

基本上,我不确定,因为虽然我的直觉说数字溢出是不好的,但我的直觉说我不应该尝试修复发布在多个地方的加密代码,因为它可能是正确的。

但是是吗?还是应该把这个数字减一?

解决方法

9007199254740992 是正确的值,如果您想要 [0,1) 中的统一值,即 0.0 <= x < 1.0

这只是自动程序出了问题,这个值可以用 JavaScript Number 准确表示,即 64 位浮点数。它只是 253,二进制 IEEE 754 浮点数处理这种形式的数字没有问题(它甚至可以用 32 位浮点数准确表示)。

使用 9007199254740991 会使范围 [0,1],即 0.0 <= x <= 1.0。大多数库在 [0,1) 中生成统一值,而其他分布则从中派生而来,但您显然可以自由地为您的应用程序做任何最好的事情。

请注意,获得最大值的实际机会是 2-53 (~1e-16),因此您不太可能在实践中真正看到它。