将Number.MAX_SAFE_INTEGER与Math.random()相乘时,我是否可能丢失任何十进制数字(精度)



在JavaScript中将Number.MAX_SAFE_INTEGER乘以Math.random()时,是否可能丢失任何十进制数字(精度(?

我想我不会,但如果能有一个可信的解释来解释原因就好了😎

编辑,通俗地说,我们处理的是两个IEEE 754双精度浮点数,一个是最大整数(用于双精度(,另一个是小数点后有几个数字的小数。如果(比如(我先把它们转换成四倍精度的格式,然后相乘,然后把乘积转换回两倍精度,结果会有什么不同吗?

const max = Number.MAX_SAFE_INTEGER;
const random = Math.random();
console.log(`
MAX_SAFE_INTEGER: ${max}, 
random: ${random}, 
product: ${max * random}`);

对于更详细的例子,我使用它来生成BigInt随机数。

您的实现应该是安全的-理论上,如果实现Math.random的引擎使用完全无偏的算法,那么0和MAX_safe_INTEGER之间的所有数字都应该有可能出现。

但规范并不能保证绝对无偏的算法——所选的数字是psuedo随机的,而不是真正的、完全的(这样的东西真的存在吗?这是有争议的…(现代版本V8和其他一些实现使用的算法的周期为2**128,比MAX_SAFE_INTEGER(2**53-1(大,但其他实现(尤其是旧的实现(的周期要小得多是完全合理的,导致该范围内的某些整数比其他整数更频繁地被选取。

如果这对您的脚本很重要(我认为在大多数情况下这是不可能的(,您可能会考虑使用比Math.random更高质量的随机生成器,但几乎肯定不值得担心。

如果(假设(我首先将它们转换为四倍精度格式,然后相乘,然后将乘积转换回两倍精度,结果会有什么不同吗?

这可能是在将两个双精度相乘与将四倍精度转换为双精度之间舍入行为不同的情况下发生的,但主要问题仍然相同。在2n到2n+1的范围内,可表示的二重之间的间距为22−52。因此,在252和253之间只能表示整数,在251到252之间只有每0.5个可以表示,等等

如果你想要更高的精度,你可以试试decimal.js。该库包含在文档页面上,所以你可以在控制台中试用。

Number.MAX_SAFE_INTEGER*.9
8106479329266892
new Decimal(Number.MAX_SAFE_INTEGER).mul(new Decimal(0.9)).toString()
"8106479329266891.9"

两个答案都是正确的,但我忍不住在C#中运行了这个小实验,其中double与JavaScript中的Number相同(fiddle(:

using System;
public class Program
{
public static void Main()
{
const double MAX_SAFE_INT = 9007199254740991;
Decimal maxD = Convert.ToDecimal(MAX_SAFE_INT.ToString());
var rng = new Random(Environment.TickCount);
for (var i = 0; i < 1000; i++) 
{ 
double random = rng.NextDouble();
double product = MAX_SAFE_INT * random;

// converting via string to workaround the "15 significant digits" limitation for Decimal(Double)
Decimal randomD = Decimal.Parse(String.Format("{0:F18}", random));

Decimal productD = maxD * randomD;
double converted = Convert.ToDouble(productD);
if (Math.Floor(converted) != Math.Floor(product)) 
{
Console.WriteLine($"{maxD}, {randomD, 22}, products: decimal {productD, 32}, converted {converted, 20}, original {product, 20}");
}
}
}
}

就我而言,我仍然得到了0 - 9007199254740991范围内随机数的期望分布。

下面是一个JavaScript游乐场代码,用于检查可能的重复出现。

相关内容

  • 没有找到相关文章