Raise 10 to a power in javascript, are there better ways than this

24,247

Solution 1

In ES5 and earlier, use Math.pow:

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

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

In ES2016 and later, use the exponentiation operator:

let result = 10 ** precision;

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

Solution 2

Why not:

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

Solution 3

if all you need to do is raise 10 to different powers, or any base to any power why not use the built in Math.pow(10,power); unless you have soe specific need to reason to reinvent the wheel

Solution 4

This has the same result as your function, but i still don't understand the application/intention.

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

Solution 5

For powers at 10³³ and above, Math.pow() may lose precision. For example:

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

While not an everyday problem that you may run into in JavaScript, it could be quite troublesome in some situations, particularly with comparison operators. One example is Google's log10Floor() function from the Closure Library:

/**
 * 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;
};

If you pass a power of 10 above 10³³, this function could return an incorrect result because Math.pow(10, 33) > 1e33 evaluates to true. The way I worked around this is to use Number coercion, concatenating the exponent to '1e':

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

And, fixing the log10Floor() function:

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;
};

Note: The bug in closure library has since been fixed.

Share:
24,247
scubasteve
Author by

scubasteve

Updated on February 07, 2020

Comments

  • scubasteve
    scubasteve about 4 years

    I have a need to create an integer value to a specific power (that's not the correct term, but basically I need to create 10, 100, 1000, etc.) The "power" will be specified as a function parameter. I came up with a solution but MAN does it feel hacky and wrong. I'd like to learn a better way if there is one, maybe one that isn't string based? Also, eval() is not an option.

    Here is what I have at this time:

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

    I also just came up with this non-string based solution, but still seems hacky due to the loop:

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

    BTW, I needed to do this to create a rounding method for working with currency. I had been using var formatted = Math.round(value * 100) / 100

    but this code was showing up all over the place and I wanted to have a method take care of the rounding to a specific precision so I created this

    if(!Math.roundToPrecision)
    {
        Math.roundToPrecision = function(value, precision)
        {
            Guard.NotNull(value, 'value');
    
            b = Math.pow(10, precision);
            return Math.round(value * b) / b;
        }  
    }
    

    Thought I'd include this here as it's proven to be handy already.

  • davin
    davin almost 13 years
    Why not just return Math.pow(base||10, precision);
  • scubasteve
    scubasteve almost 13 years
    Sad to say, I wasn't aware of the pow() method, it's exactly what I needed. However, I'd still like to learn how it's done; any idea what Math.pow() may be doing behind the covers?
  • davin
    davin almost 13 years
    @Steve, like most math libraries they probably implement numerical approximations of functions with the standards-required precision. Since Math.pow isn't just for integers, it's implementation has to be generic for all "real" numbers so it's not something similar to your loop implementation (which wouldn't work on a base of say, 5.672 for example); Maybe a taylor expansion or something similar.
  • scubasteve
    scubasteve almost 13 years
    @Davin - I googled "taylor expansion" and upon reading the first paragraph from Wikipedia blood began trickling from my ears as my vision blurred... I will just accept that Math.pow() is cool. ;0)
  • davin
    davin almost 13 years
    @Steve, hmmm, so you can rework the equation as follows: we want the value of y=x^n, so we write ln(y) = ln(x^n) = n*ln(x) and raising both sides to the power of the natural base e we get y = exp(n*ln(x)) and now you can calculate ln(x) with a taylor expansion to any required precision in a predetermined number of steps, multiple by n, and calculate the exp function of the product, again with a taylor expansion to the required number of terms i.e. the required precision.
  • davin
    davin almost 13 years
    @Steve, yeah, those wiki articles are written to make us all feel dumb :) Or to make their authors feel smart. In any case, if you pick up a text book on real analysis their should be sufficient material to understand taylor expansions to quite some depth, although that blood-from-the-ears symptom might return.
  • Shad
    Shad almost 13 years
    @davin True, just an initialization habit =)
  • scubasteve
    scubasteve almost 13 years
    @Davin Thanks for the additional info, it demystifies some of what was said earlier.