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

问题描述

我正在处理一项看似典型的面试任务 - 通过该数字的指数计算斐波那契数。但是任务的难点是索引可以达到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 函数中(或在传入后将其转换为一个),并确保每个数字文字都是 BigInt 文字(例如使用 {{ 1}} 而不是 2n)。有一个警告 - BigInt 必须是一个整数,它不能保存十进制值。这可能需要对您的算法进行一些调整。

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