【问题标题】:Raise 10 to a power in javascript, are there better ways than this在 javascript 中提高 10 的幂,有没有比这更好的方法
【发布时间】:2011-09-11 07:26:52
【问题描述】:

我需要创建一个特定幂的整数值(这不是正确的术语,但基本上我需要创建 10、100、1000 等)“幂”将被指定为函数参数。我想出了一个解决方案,但 MAN 确实觉得它很笨拙和错误。如果有一种方法,也许不是基于字符串的方法,我想学习一种更好的方法?此外,eval() 不是一个选项。

这是我目前拥有的:

function makeMultiplierBase(precision)
{
    var numToParse = '1';
    for(var i = 0; i < precision; i++)
    {
        numToParse += '0';
    }

    return parseFloat(numToParse);
}

我也刚刚想出了这个基于非字符串的解决方案,但由于循环,它仍然看起来很老套:

function a(precision)
{
    var tmp = 10;
    for(var i = 1; i < precision; i++)
    {
        tmp *= 10;
    }

    return tmp;
}

顺便说一句,我需要这样做来创建一种用于处理货币的舍入方法。我一直在使用 var formatted = Math.round(value * 100) / 100

但是这段代码到处都是,我想要一个方法来处理舍入到特定的精度,所以我创建了这个

if(!Math.roundToPrecision)
{
    Math.roundToPrecision = function(value, precision)
    {
        Guard.NotNull(value, 'value');

        b = Math.pow(10, precision);
        return Math.round(value * b) / b;
    }  
}

我想我会把它包括在这里,因为它已经被证明很方便。

【问题讨论】:

  • 那么,你为什么将它设为浮点数而不是整数?
  • @Shad 你指的是 parseFloat() 调用?如果是这样,我想这只是一个疏忽, Number(numToParse) 也会起作用

标签: javascript exponentiation


【解决方案1】:

在 ES5 及更早版本中,使用 Math.pow:

var result = Math.pow(10, precision);

var precision = 5;
var result = Math.pow(10, precision);
console.log(result);

在 ES2016 及更高版本中,使用 exponentiation operator:

let result = 10 ** precision;

let precision = 5;
let result = 10 ** precision;
console.log(result);

【讨论】:

  • 遗憾的是,我不知道 pow() 方法,这正是我所需要的。但是,我仍然想了解它是如何完成的;知道 Math.pow() 可能在幕后做什么吗?
  • @Steve,像大多数数学库一样,它们可能以标准要求的精度实现函数的数值逼近。由于Math.pow 不仅适用于整数,因此它的实现必须对所有“实数”数字都是通用的,因此它与您的循环实现不同(例如,在 5.672 的基础上不起作用);也许是泰勒扩展或类似的东西。
  • @Davin - 我在谷歌上搜索了“泰勒扩展”,在阅读维基百科的第一段后,随着我的视线模糊,血液开始从我的耳朵里流淌出来......我只会接受 Math.pow() 很酷. ;0)
  • @Steve,嗯,所以你可以修改方程如下:我们想要y=x^n的值,所以我们写ln(y) = ln(x^n) = n*ln(x)并将两边都提升到自然基础@987654330的幂@ 我们得到y = exp(n*ln(x)),现在您可以用泰勒展开式计算ln(x),以预定步数乘以n,并乘以n,并再次使用泰勒计算乘积的exp函数扩展到所需的项数,即所需的精度。
  • @Steve,是的,那些 wiki 文章是为了让我们都觉得自己很笨 :) 或者让他们的作者觉得自己很聪明。无论如何,如果你拿起一本关于真实分析的教科书,它们应该足以让你深入了解泰勒展开式,尽管耳中出血的症状可能会再次出现。
【解决方案2】:

我在浏览https://github.com/aecostas/huffman 时偶然发现了一些东西。编译后的code(js)有一行

alphabet_next = sorted.slice(0, +(sorted.length - 1 - groupsize) + 1 || 9e9);

如果您尝试评估 9e9(在节点和浏览器控制台上),它会给您 9000000000,即“9*10^9”。基于此,您只需执行以下操作即可获得 10 次方。 var n = 2; eval("1e"+n); //outputs 100

编辑:关于指数符号的更多信息来自 http://www.2ality.com/2012/03/displaying-numbers.html.

JavaScript 使用两种十进制表示法: 固定表示法 [“+”| "-" ] 数字+ [ "."数字+] 和指数符号 [“+”| “-“ ] 数字 [ ”。”数字+ ] "e" [ "+" | "-" ] 数字+ 指数符号的一个示例是 -1.37e+2。对于输出,点前始终只有一位数字,对于输入,您可以使用多个数字。指数符号解释如下: 给定一个指数符号: 有效和指数。 该数字的值是 有效数 × 10指数。 因此,-1.37e+2 表示数字 -137。

【讨论】:

    【解决方案3】:

    对于 10³³ 及以上的幂,Math.pow() 可能会丢失精度。例如:

    Math.pow(10, 33);    //-> 1.0000000000000001e+33
    Math.pow(10, 34);    //-> 1.0000000000000001e+34
    Math.pow(10, 35);    //-> 1e+35
    Math.pow(10, 36);    //-> 1e+36
    Math.pow(10, 37);    //-> 1.0000000000000001e+37
    

    虽然您在 JavaScript 中可能会遇到日常问题,但在某些情况下可能会非常麻烦,尤其是比较运算符。一个例子是来自 Closure 库的 Google 的 log10Floor() 函数:

    /**
     * Returns the precise value of floor(log10(num)).
     * Simpler implementations didn't work because of floating point rounding
     * errors. For example
     * <ul>
     * <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3.
     * <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15.
     * <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1.
     * </ul>
     * @param {number} num A floating point number.
     * @return {number} Its logarithm to base 10 rounded down to the nearest
     *     integer if num > 0. -Infinity if num == 0. NaN if num < 0.
     */
    goog.math.log10Floor = function(num) {
      if (num > 0) {
        var x = Math.round(Math.log(num) * Math.LOG10E);
        return x - (Math.pow(10, x) > num);
      }
      return num == 0 ? -Infinity : NaN;
    };
    

    如果您传递 10³³ 以上的 10 的幂,则此函数可能会返回不正确的结果,因为 Math.pow(10, 33) &gt; 1e33 的计算结果为 true。我解决这个问题的方法是使用数字强制,将指数连接到“1e”:

    +'1e33'    //-> 1e+33
    +'1e34'    //-> 1e+34
    +'1e35'    //-> 1e+35
    +'1e36'    //-> 1e+36
    +'1e37'    //-> 1e+37
    

    并且,修复 log10Floor() 函数:

    goog.math.log10Floor = function(num) {
      if (num > 0) {
        var x = Math.round(Math.log(num) * Math.LOG10E);
        return x - (+('1e' + x) > num);
      }
      return num == 0 ? -Infinity : NaN;
    };
    

    注意:闭包库中的错误自此为fixed

    【讨论】:

      【解决方案4】:

      使用查找表。但如果这是为了四舍五入货币金额,您应该使用 BigDecimal 而不是整个 schemozzle。

      【讨论】:

        【解决方案5】:

        这与您的功能具有相同的结果,但我仍然不了解应用程序/意图。

        function makeMultiplierBase(precision,base){
            return Math.pow(base||10,precision);
        }
        

        【讨论】:

        • 为什么不只是return Math.pow(base||10, precision);
        • @davin 没错,只是一个初始化习惯 =)
        【解决方案6】:

        如果您需要做的只是将 10 提升到不同的权力,或者任何权力的任何基础,为什么不使用内置的 Math.pow(10,power); 除非您有特殊需要重新发明轮子的理由

        【讨论】:

          【解决方案7】:

          为什么不:

          function precision(x) {  
            return Math.pow(10, x);
          }
          

          【讨论】:

            猜你喜欢
            • 2021-04-17
            • 2016-04-02
            • 1970-01-01
            • 1970-01-01
            • 2021-01-13
            • 1970-01-01
            • 2019-11-06
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多