一、问题:

JavaScript的Math对象中有一个方法Math.pow(x, y),用来求x的y次方。它有一个问题,即当x<0且y<1的时候,它总是返回NaN。对于x<0且1/y为偶数时,它返回NaN是有道理的,因为负数不能够被开偶数次方根。但是对于x<0且1/y为奇数时,返回NaN就没有道理了,因为负数也可以被开奇数次方根。

即JavaScript的Math.pow(x, y)方法,不支持对负数求奇次方根。

举例来说明:

测试用例

说明

JavaScript 返回结果

实际应返回结果

是否通过测试?

Math.pow(16, 1/2) 16^(1/2),即对16开平方 4 4 通过
Math.pow(-16, 1/2) (-16)^(1/2),即对-16开平方 NaN NaN 通过
Math.pow(27, 1/3) 27^(1/3),即对27开立方 3 3 通过
Math.pow(-27, 1/3) (-27)^(1/3),即对-27开立方 NaN -3 失败!

注:以上均在实数范围内讨论。

二、问题原因:

估计JavaScript的Math.pow(x, y)方法,是使用对数逼近的途径来对x的奇次方根求解的,而对数函数的定义域不包括负数,于是产生了这个问题。

三、解决方案:

    Math.power = Math.pow;
    //
    // 让Math.pow(x, y)支持对x求奇次方根
    //
    Math.pow = function (x, y) {
        if (y < 1 && 1 / y % 2 == 1 && x < 0) {
            return -Math.power(-x, y);
        } else {
            return Math.power(x, y);
        }
    };

四、检验:

在进行修正后,再运行以上的测试用例,则全部通过。

  <td width="138" align="center">
    <p align="center"><strong>说明</strong></p>
  </td>

  <td width="89" align="center">
    <p align="center"><strong>修正后JavaScript 返回结果</strong></p>
  </td>

  <td width="73" align="center">
    <p align="center"><strong>实际应返回结果</strong></p>
  </td>

  <td width="77" align="center">
    <p align="center"><strong>是否通过测试?</strong></p>
  </td>
</tr>

<tr>
  <td valign="top" width="173"><a title="点击这里运行!" href="http://www.myfootprints.cn/OldWeb/javascript/default.asp?s=%20%20%20%20Math.power%20%3D%20Math.pow%3B%0A%20%20%20%20%2F%2F%0A%20%20%20%20%2F%2F%20%E8%AE%A9Math.pow(x%2C%20y)%E6%94%AF%E6%8C%81%E5%AF%B9x%E6%B1%82%E5%A5%87%E6%AC%A1%E6%96%B9%E6%A0%B9%0A%20%20%20%20%2F%2F%0A%20%20%20%20Math.pow%20%3D%20function%20(x%2C%20y)%20%7B%0A%20%20%20%20%20%20%20%20if%20(y%20%3C%201%20%26%26%201%20%2F%20y%20%25%202%20%3D%3D%201%20%26%26%20x%20%3C%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20-Math.power(-x%2C%20y)%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Math.power(x%2C%20y)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20alert(Math.pow(16%2C%201%2F2))%3B" target="_blank">Math.pow(16, 1/2)</a></td>

  <td valign="top" width="138">16^(1/2),即对16开平方</td>

  <td valign="top" width="89">4</td>

  <td valign="top" width="73">4</td>

  <td valign="top" width="77">通过</td>
</tr>

<tr>
  <td valign="top" width="173"><a title="点击这里运行!" href="http://www.myfootprints.cn/OldWeb/javascript/default.asp?s=%20%20%20%20Math.power%20%3D%20Math.pow%3B%0A%20%20%20%20%2F%2F%20%E8%AE%A9Math.pow(x%2C%20y)%E6%94%AF%E6%8C%81%E5%AF%B9x%E6%B1%82%E5%A5%87%E6%AC%A1%E6%96%B9%E6%A0%B9%0A%20%20%20%20Math.pow%20%3D%20function%20(x%2C%20y)%20%7B%0A%20%20%20%20%20%20%20%20if%20(y%20%3C%201%20%26%26%201%20%2F%20y%20%25%202%20%3D%3D%201%20%26%26%20x%20%3C%200)%20%7B%20return%20-Math.power(-x%2C%20y)%3B%7D%20else%20%7B%20return%20Math.power(x%2C%20y)%3B%7D%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20alert(Math.pow(-16%2C%201%2F2))%3B" target="_blank">Math.pow(-16, 1/2)</a></td>

  <td valign="top" width="138">(-16)^(1/2),即对-16开平方</td>

  <td valign="top" width="89">NaN</td>

  <td valign="top" width="73">NaN</td>

  <td valign="top" width="77">通过</td>
</tr>

<tr>
  <td valign="top" width="173"><a title="点击这里运行!" href="http://www.myfootprints.cn/OldWeb/javascript/default.asp?s=%20%20%20%20Math.power%20%3D%20Math.pow%3B%0A%20%20%20%20%2F%2F%20%E8%AE%A9Math.pow(x%2C%20y)%E6%94%AF%E6%8C%81%E5%AF%B9x%E6%B1%82%E5%A5%87%E6%AC%A1%E6%96%B9%E6%A0%B9%0A%20%20%20%20Math.pow%20%3D%20function%20(x%2C%20y)%20%7B%0A%20%20%20%20%20%20%20%20if%20(y%20%3C%201%20%26%26%201%20%2F%20y%20%25%202%20%3D%3D%201%20%26%26%20x%20%3C%200)%20%7B%20return%20-Math.power(-x%2C%20y)%3B%7D%20else%20%7B%20return%20Math.power(x%2C%20y)%3B%7D%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20alert(Math.pow(27%2C%201%2F3))%3B" target="_blank">Math.pow(27, 1/3)</a></td>

  <td valign="top" width="138">27^(1/3),即对27开立方</td>

  <td valign="top" width="89">3</td>

  <td valign="top" width="73">3</td>

  <td valign="top" width="77">通过</td>
</tr>

<tr>
  <td valign="top" width="173"><a title="点击这里运行!" href="http://www.myfootprints.cn/OldWeb/javascript/default.asp?s=%20%20%20%20Math.power%20%3D%20Math.pow%3B%0A%20%20%20%20%2F%2F%20%E8%AE%A9Math.pow(x%2C%20y)%E6%94%AF%E6%8C%81%E5%AF%B9x%E6%B1%82%E5%A5%87%E6%AC%A1%E6%96%B9%E6%A0%B9%0A%20%20%20%20Math.pow%20%3D%20function%20(x%2C%20y)%20%7B%0A%20%20%20%20%20%20%20%20if%20(y%20%3C%201%20%26%26%201%20%2F%20y%20%25%202%20%3D%3D%201%20%26%26%20x%20%3C%200)%20%7B%20return%20-Math.power(-x%2C%20y)%3B%7D%20else%20%7B%20return%20Math.power(x%2C%20y)%3B%7D%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20alert(Math.pow(-27%2C%201%2F3))%3B" target="_blank">Math.pow(-27, 1/3)</a></td>

  <td valign="top" width="138">(-27)^(1/3),即对-27开立方</td>

  <td valign="top" width="89">-3</td>

  <td valign="top" width="73">-3</td>

  <td valign="top" width="77">通过</td>
</tr>

测试用例