斐波那契任务。 BigInt 不同于数字

Fibonacci task. BigInt differs from a number

我正在处理一个看似典型的面试任务 - 通过该数字的索引计算斐波那契数。但是这个任务的难点在于索引可以达到2000000。我遇到了几个问题,我不明白为什么会这样。

首先是代码:

function fib(number) {  
  const left = Math.pow((1 + Math.sqrt(5)) / 2, number);
  const right = Math.pow((1 - Math.sqrt(5)) / 2, number);
  const result = Math.round((left - right) / Math.sqrt(5));
  
  console.log(result); // 
  return BigInt(result); // 
}

问题:

  1. BigInt 不同于数字
fib(96);
console.log(result) // -> 51680708854858490000
BigInt(result) // 51680708854858489856
  1. 错误答案。我觉得跟之前的问题有关
fib(96);
// Must return 51680708854858323072
// But return BigInt 51680708854858489856

Javascript 数字默认存储为浮点数,这意味着它们以科学记数法存储在内存中(除非您使用 BigInt),并且它们只能保持有限的精度。因此,一个大数字有点像这样表示:1.2345 * 10^12,并且存储在内存中的 . 之后的位数是有限制的。您正在处理一些非常大的数字,并且溢出了单个浮点数可以容纳的精度,这就是您的计算最终出错的原因。 BigInt 是解决这个问题的方法,因为它不以科学记数法存储数字,并且可以容纳任意数量的数字。但是,您必须在整个计算过程中一直使用 BigInt - 您不能只在最后将科学计数法数字转换为 BigInt 并期望额外的精度突然出现。

因此,为了使其正常工作,请确保将 BigInt 作为参数传递给 fib 函数(或在传入后将其转换为 1),并确保每个数字文字都是 BigInt 文字(例如使用2n 而不是 2)。有一个警告 - BigInt 必须是整数,它不能保存小数值。这可能需要对您的算法进行一些调整。

如果您想了解更多关于浮点数的具体细节,以及它们可以保持多少精度,请查看this Wikipedia article