2

I've used Math.pow() to calculate the exponential value in my project.

Now, For specific values like Math.pow(3,40), it returns 12157665459056929000.

But when i tried the same value using a scientific Calculator, it returns 12157665459056928801.

Then i tried to traverse the loop till the exponential value :

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

This also returns 12157665459056929000. Is there any restriction to Int type in JS ?

Hanky Panky
  • 46,730
  • 8
  • 72
  • 95
Janak
  • 4,986
  • 4
  • 27
  • 45
  • 2
    Who is to define whether that `scientific calculator` is authentic or `math.pow`? Did you try any third method? If there is any limit, it is being applied to the result of scientific calculator, that is the lesser value – Hanky Panky Nov 22 '13 at 05:47
  • 1
    The scientific calculator is correct in this case. – Joseph Myers Nov 22 '13 at 05:47
  • @JosephMyers At least the number is odd which hints that it is more likely to be correct... – sashkello Nov 22 '13 at 05:48
  • @JosephMyers how? can you back that up with an argument? – Hanky Panky Nov 22 '13 at 05:48
  • I recently read a blog post about this, but I cannot find it. The closest thing I could find is here: http://stackoverflow.com/questions/588004/is-javascripts-floating-point-math-broken . Basically, I think it is because javascript uses 64 bit, and then eventually when the numbers get large enough it starts to give you the same number for every for 2 powers in a row before changing. – drneel Nov 22 '13 at 05:50
  • @Hanky : There is no authenticity to that calculator. but i compared my result with the calci because that was the only place i got a different answer. The calci I used was the one available with the windows-7 – Janak Nov 22 '13 at 06:36

5 Answers5

4

This behavior is highly dependent on the platform you are running this code at. Interestingly even the browser matters even on the same very machine.

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

On my 64-bit machine Here are the results:

IE11: 12157665459056928000

FF25: 12157665459056929000

CH31: 12157665459056929000

SAFARI: 12157665459056929000

Hanky Panky
  • 46,730
  • 8
  • 72
  • 95
  • It's really odd that IE11 is 1000 off .. it *should* be consistent, I think. – user2864740 Nov 22 '13 at 05:59
  • You can try it for your machine and see if they are different? – Hanky Panky Nov 22 '13 at 05:59
  • I don't have IE11, but IE10/Win7/x64 reports "12157665459056928000" as well. – user2864740 Nov 22 '13 at 06:00
  • I've voted this up, because I think that it's curious that the pow function behaves differently - at least at the limits. I did not expect that behavior, even if I did expect losing bits of information. – user2864740 Nov 22 '13 at 06:07
  • `12157665459056928000 === 12157665459056929000` (IE11 just decided to convert it to a string differently, but they are both the same number. Unsurprising since they all probably use `pow` from the C runtime) – Artyer Feb 02 '22 at 21:40
3

52 bits of JavaScript's 64-bit double-precision number values are used to store the "fraction" part of a number (the main part of the calculations performed), while 11 bits are used to store the "exponent" (basically, the position of the decimal point), and the 64th bit is used for the sign. (Update: see this illustration: http://en.wikipedia.org/wiki/File:IEEE_754_Double_Floating_Point_Format.svg)

There are slightly more than 63 bits worth of significant figures in the base-two expansion of 3^40 (63.3985... in a continuous sense, and 64 in a discrete sense), so hence it cannot be accurately computed using Math.pow(3, 40) in JavaScript. Only numbers with 52 or fewer significant figures in their base-two expansion (and a similar restriction on their order of magnitude fitting within 11 bits) have a chance to be represented accurately by a double-precision floating point value.

Take note that how large the number is does not matter as much as how many significant figures are used to represent it in base two. There are many numbers as large or larger than 3^40 which can be represented accurately by JavaScript's 64-bit double-precision number values.

Note:

3^40 = 1010100010111000101101000101001000101001000111111110100000100001 (base two)

(The length of the largest substring beginning and ending with a 1 is the number of base-two significant figures, which in this case is the entire string of 64 digits.)

Joseph Myers
  • 6,434
  • 27
  • 36
1

JavaScript can only represent distinct integers to 253 (or ~16 significant digits). This is because all JavaScript numbers have an internal representation of IEEE-754 base-2 doubles.

As a consequence, the result from Math.pow (even if was accurate internally) is brutally "rounded" such that the result is still a JavaScript integer (as it is defined to return an integer per the specification) - and the resulting number is thus not the correct value, but the closest integer approximation of it JavaScript can handle.

I have put underscores above the digits that don't [entirely] make the "significant digit" cutoff so it can be see how this would affect the results.

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

Another way to see this is to run the following (which results in true):

12157665459056928801 == 12157665459056929000

From the The Number Type section in the specification:

Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the Number type ..

.. but not all integers with large magnitudes are representable.


The only way to handle this situation in JavaScript (such that information is not lost) is to use an external number encoding and pow function. There are a few different options mentioned in https://stackoverflow.com/questions/287744/good-open-source-javascript-math-library-for-floating-point-operations and Is there a decimal math library for JavaScript?

For instance, with big.js, the code might look like this fiddle:

var z = new Big(3)
var r = z.pow(40)
var str = r.toString()
// str === "12157665459056928801"
Community
  • 1
  • 1
user2864740
  • 60,010
  • 15
  • 145
  • 220
1

Haskell (ghci) gives

Prelude> 3^40
12157665459056928801

Erlang gives

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

You get 12157665459056929000 because it uses IEEE floating point for computation. You get 12157665459056928801 because it uses arbitrary precision (bignum) for computation.

0

Can't say I know for sure, but this does look like a range problem.

I believe it is common for mathematics libraries to implement exponentiation using logarithms. This requires that both values are turned into floats and thus the result is also technically a float. This is most telling when I ask MySQL to do the same calculation:

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

It might be a courtesy that you are actually getting back a large integer.

staticsan
  • 29,935
  • 4
  • 60
  • 73