Math.pow()没有给出准确的答案

时间:2013-11-22 05:44:03

标签: javascript math integer user-defined-functions

我使用Math.pow()来计算项目中的指数值。

现在,对于Math.pow(3,40)等特定值,它会返回12157665459056929000

但是当我使用科学计算器尝试相同的值时,它会返回12157665459056928801

然后我试图遍历循环直到指数值:

  function calculateExpo(base,power){
    base = parseInt(base);
    power = parseInt(power);
    var output = 1;
    gameObj.OutPutString = '';  //base + '^' + power + ' = ';
    for(var i=0;i<power;i++){
      output *= base;
      gameObj.OutPutString += base + ' x ';
    }
    // to remove the last comma 
    gameObj.OutPutString = gameObj.OutPutString.substring(0,gameObj.OutPutString.lastIndexOf('x'));
    gameObj.OutPutString += ' =  ' + output;
    return output;
  }

这也会返回12157665459056929000。 JS中的Int类型是否有任何限制?

5 个答案:

答案 0 :(得分:3)

此行为高度依赖于您运行此代码的平台。有趣的是,即使浏览器甚至在同一台机器上也很重要。

<script>
document.write(Math.pow(3,40));
</script>

在我的64位计算机上以下是结果:

IE11 12157665459056928000

FF25 12157665459056929000

CH31 12157665459056929000

SAFARI: 12157665459056929000

答案 1 :(得分:3)

52位JavaScript的64位双精度数值用于存储数字的“分数”部分(执行计算的主要部分),而11位用于存储“指数”(基本上,小数点的位置),第64位用于符号。 (更新:请参阅此插图:http://en.wikipedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg

3^40的基础扩展中有大约63位有效数字(连续意义上为63.3985 ......在离散意义上为64),因此无法准确在JavaScript中使用Math.pow(3, 40)计算。只有在其基数为2的扩展中具有52或更少有效数字的数字(以及对其在11位内的数量级的类似限制)才有机会通过双精度浮点值准确表示。

请注意,数字的大小与在基数2中使用多少有效数字无关紧要。有许多数字大于或大于3^40可以通过JavaScript的64位双精度数值精确表示。

注意:

3^40 = 1010100010111000101101000101001000101001000111111110100000100001(基数为二)

(以1开头和结尾的最大子串的长度是基数为2的有效数字,在这种情况下是64位数的整个字符串。)

答案 2 :(得分:1)

JavaScript只能代表 distinct 整数to 253(或~16位有效数字)。这是因为所有 JavaScript数字的内部表示形式为IEEE-754 base-2 double。

因此,Math.pow的结果(即使 内部准确)是残酷的“舍入”,结果仍然是JavaScript整数(因为它被定义为返回每个规范的整数) - 结果数字因此正确的值,但JavaScript可以处理的最接近整数近似值。

我已将下划线放在数字之上,而这些数字并未[完全]使“有效数字”截止,因此可以看出这会对结果产生怎样的影响。

................____
12157665459056928801     - correct value
12157665459056929000     - closest JavaScript integer

另一种看到这种情况的方法是运行以下命令(结果为true):

12157665459056928801 == 12157665459056929000

来自规范中的The Number Type部分:

  

请注意,数量类型不超过2 53 的所有正整数和负整数都可以在数字类型中表示。

..但并非所有具有大幅度的整数都是可表示的。


在JavaScript中处理这种情况的唯一方法(使信息不会丢失)是使用外部编号和pow函数。 https://stackoverflow.com/questions/287744/good-open-source-javascript-math-library-for-floating-point-operationsIs there a decimal math library for JavaScript?

中提到了一些不同的选项

例如,对于big.js,代码可能看起来像this fiddle

var z = new Big(3)
var r = z.pow(40)
var str = r.toString()
// str === "12157665459056928801"

答案 3 :(得分:1)

Haskell(ghci)给出了

Prelude> 3^40
12157665459056928801

Erlang给出了

1> io:format("~f~n", [math:pow(3,40)]).
12157665459056929000.000000
2> io:format("~p~n", [crypto:mod_exp(3,40,trunc(math:pow(10,21)))]).
12157665459056928801

的JavaScript

> Math.pow(3,40)
  12157665459056929000

您得到12157665459056929000,因为它使用IEEE浮点进行计算。得到12157665459056928801因为它使用任意精度(bignum)进行计算。

答案 4 :(得分:0)

不能说我肯定知道,但这看起来像是一个范围问题。

我认为数学库通常使用对数来实现取幂。这要求两个值都变成浮点数,因此结果在技术上也是浮点数。当我要求MySQL进行相同的计算时,这是最有说服力的:

> select pow(3, 40);
+-----------------------+
| pow(3, 40)            |
+-----------------------+
| 1.2157665459056929e19 |
+-----------------------+

你实际上回到一个大整数可能是礼貌的。