JS programs for big numbers?


#1

Does anyone know a program that lets you run loops and doesn’t stop you after 99 intervals? Im trying to calculate 2e+ 5000 because i haven’t been able to find a calculator that can do that. So i am trying to build a simple loop that pushes 0 on the end of 1, 5000 times. Now repl.it stops you before 5000 (99)


#2

2e+5000 is far too large than a number's max value of 1.79e+308. There could be libraries for handling really large numbers if you really need to, but I’m not aware of any.


#3

Well, of course locally, in your own browser you can loop as much as you want. Some sandboxes may limit you to prevent infinite loops. Sometimes there is a way to defeat the infinite loop protection - but only use it if you’re sure.

But the bigger problem is just that JS can’t handle those numbers. The max safe int is usually around 2^31-1 - above that things start to get approximate.

There are libraries you can use. Or you can use a language made for that kind of math.


#4

Try wolfram alpha.

Here’s 2e^5000 x pi


#5

Javascript sandbox is single-threaded, meaning if you don’t relinquish control ASAP things won’t get updated and the tab will look frozen (Not Responding message on Firefox).
Calculating big numbers is CPU bound, hence will keep control of the thread.
In order to tackle with this, Web Workers have been introduced into JS engine. Check it out.

Here’s an example of just what you ask: https://bilgiprog.github.io/jsders/byksay/byk.html
It’s in Turkish, but that doesn’t matter, the interface is simple. First textbox is base, second textbox is exponent, check Worker kullan box then click Hesapla. It uses some bigint library. (If you don’t check Worker, it will try to calculate on the single thread and freeze the tab).


#6

Most languages won’t work well for numbers that large, computers are not good at dealing with [non-binary] numerical calculations at the best of times. JS in particular only has one number type and is generally a very bad choice for precision maths-based stuff. There are workarounds, like the aforementioned BigInt library, but it just isn’t going to work better than a calculator, the language isn’t designed to be decent at doing that. Basically, Replit stops you because the numbers involved are far too large, it isn’t going to sit and wait a few hours/days/etc while you use up the available memory on their server.


#7

I got curious and, one thing led to another, I decided to write an algorithm as a learning exercise because it seems like an interesting problem to play with.

The approach I took involves using strings as input and output, and splitting a given string into chunks smaller than 16 digits for the calculations in between (15 is optimal in this case). The code appended (no effort spent on optimisation) works in repl.it for 25000 on my laptop (results verified programmatically for up to 253, the last power of 2 with less than 16 digits; larger numbers were checked against this article on Wiki and even larger numbers were compared to those produced by the demo that @alper6 posted).

My code only works for powers of 2 (can be generalised). It’s thread-blocking and appears to be slower than using workers (don’t know how to work with them yet :frowning:), but calculating 25000 takes less than 200ms with my setup and may be good enough for you if you just need something on repl.it for demonstration purposes.

@DanCouper If I’m not mistaken, code on repl.it is executed client-side. For example, the code below has significantly different average execution times in Firefox (~160ms) and Chrome (~270ms); the iteration threshold that would set off the warning for a potential infinite loop warning is different for different browsers; and CPU usage shoots up for the duration when the code is run. As an aside, the threshold for potentially infinite loops seems to be higher for codepen (I could calculate 220000).

function multiplyByTwo(str) {
  const arrLength = Math.ceil(str.length / intSize);
  const arr = [];
  
  for (let i = 0; i < arrLength; i++) {
    arr.push(str.slice(i * intSize, i * intSize + intSize))
  }

  const arrReversed = arr.reverse();
  const arrReversedDoubled = arrReversed.map((val) => (parseInt(val) * 2).toString());
  
  return arrReversedDoubled.map((val, i) => {
    let adjustedVal = val;
    
    // Add one if the previous number has excess
    if (i !== 0) {
      const prevLengthDifference = arrReversedDoubled[i - 1].length - arrReversed[i - 1].length;
      
      adjustedVal = prevLengthDifference > 0
        ? (parseInt(adjustedVal) + 1).toString()
        : adjustedVal;
    }
    
    // Trim excess and add leading zeroes
    if (i !== arrLength - 1) {
      const lengthDifference = adjustedVal.length - arrReversed[i].length;
      
      adjustedVal = lengthDifference > 0
        ? adjustedVal.slice(1)
        : '0'.repeat(Math.abs(lengthDifference)) + adjustedVal;
    }
    
    return adjustedVal;
  }).reverse().join('');
}

function twoToThePowerOf(power) {
  let q = '1';
  
  for (let i = 0; i < power; i++) {
    q = multiplyByTwo(q);
    
    // Test for up to 2^53, the last number with less than 17 digits
    // if (parseInt(q) !== 2 ** (i + 1)) {
    //   console.error('(Failed) 2^${i + 1}: ${q}');
    // }
    // else {
    //   console.log(`(Pass) 2^${i + 1}: ${q}`);
    // }
  }
  
  return q;
}


const intSize = 15;
const y = 5000;
const x = twoToThePowerOf(y);
const iterations = 30;
let t = 0;

for (let i = 0; i < iterations; i++) {
  const t0 = performance.now();
  twoToThePowerOf(y);
  const t1 = performance.now();
  
  t += t1 - t0;
}

console.log(x);
console.log(`Number of digits: ${x.length}`);
console.log(`Average execution time: ${(t / iterations).toFixed(3)}ms`)

#8

One common solution is to use strings as numbers. With that you can use integers as big as strings. I think max string sizes get up above 250M chars, so that would get you above 10^250000000. This is a library that does it all for you.


#9

Ah, it might be client side for some JS stuff (just basic is rather than es6 possibly?). Generally it takes the code, stringifies it, sends it to the replit servers and runs eval on that for whatever language is being used, then spits the result back; the guy who built it described it as “eval as a service”


#10

Yeah but how to add those strings of zero’s without a loop?

I never expected this thread to get this many replies, guess it was a interesting topic to everyone :slight_smile: .
I thought this would of been considered a “spam” thread at first.

@alper6 I checked it out, and its confusing, help?

@owel For some reason i get a image of the number, so i cant copy and paste it or use it.

@ksjazzguitar I tried looping through, pushing zero around 100 times to a array, then tried pushing it 50 times into another string that contained a 1, didn’t work for some reason.


#11

I don’t know what to say, I found it quite easy, here’s a pen,

Maybe I’m misunderstanding what you’re trying to do. Can you provide the code?


#12

@DanCouper I see! I tried running code just now after turning Wi-Fi off and the code would still run (the in-browser console is updated every time I press run), it just wouldn’t save (as expected). I tried print("Hello World!") with Python and the code wouldn’t run without connection. It seems like JavaScript may be an exception because it can run natively in browsers.

@John-freeCodeCamp You may have missed my earlier post because I forgot to tag you or that I decided to blur some bits in case you wanted to figure it out yourself—the code was tested in repl.it and it uses a string as input, splits the string into into an array of smaller strings to perform calculations on, and gives you a string as an output.


#13

@ksjazzguitar - I built this on repl.it, so that is why it was limiting me. Yes your code does work, but normally your loop would be limited and that was my issue. Thanks

@honmanyau - I saw the code, but i’m still confused on what it is doing. Looks very complicated. So your just splitting it up among multiple loops?


#14

I can’t think of a way that you can calculate anything larger than 253 without using any loops because of the limit mentioned above. At this point, it may be better to post the code that you were using, or clarify what repl.it stops you" means if loops seem to be a problem for you somehow—even on repl.it I could push ~1.2 million zeros into an array in on my laptop and ~0.7 million zeroes on my phone before it starts complaining about potentially infinite loops.

As for the code I posted, the multiplyByTwo() method does the following:

  1. Takes a string input and split it into an array of substrings defined by intSize—this number can be any positive integers up to, and including, 15. 15 appears to be the ideal size because it’s the largest size that you can double as an integer safely without running into the limit of 253, a larger substring size is presumably better because it reduces the number of operations in between, if we use 4096 as an example and intSize = 2 as an example, the array of substrings would like like this:
console.log(arr); // prints ["40", "96"]
  1. The array of substrings is reversed (oops, I just realised that reversing is unnecessary, please ignore this for the steps below, particular in cases where the position of a substring is discussed)
  2. Each substring in the array is converted to an integer with parseInt(), multiplied by 2m and then converted back to a string, continuing with the example of 4096 from above:
console.log(arr); // prints ["40", "96"]
console.log(arrDoubled); // prints ["80", "192"]
  1. For each substring in a given position n, increment by 1 if the substring in the n + 1 position has a length of longer than 15—this is to carry any excess of 1 over as you would in column addition (note that this excess can only ever be 1 when multiplying a number by 2), suppose we capture the array at this point and assign it to intermediate:
console.log(arr); // prints ["40", "96"]
console.log(arrDoubled); // prints ["80", "192"]
console.log(intermediate); // prints ["81", "192"]
  1. Since any excess have already been taken care of, we can safely remove them at this point:
console.log(arr); // prints ["40", "96"]
console.log(arrDoubled); // prints ["80", "192"]
console.log(intermediate); // prints ["81", "192"]
console.log(intermediate); // prints ["81", "92"]
  1. “Leading zeros” are also added at this point if necessary. This operation is done because converting a substring of, for example, parseInt('04') would gives 4, doubling it and then parse it back into a string is "8" instead of the desired "08"

  2. The result of multiplying the input by 2 is then produced simply by joining the substrings using the join('') method

The twoToThePowerOf() method simply loops through multiplyByTwo() for a n number of times to calculate 2n.

I hope that helps. :slight_smile:


#15

I don’t know what looks confusing to you, it’s just 2 textboxes one button and one checkbox as I explained.
Try with a 6-digit exponent to observe the effect of Worker. It takes ~12 sec on my laptop to calculate 8 to 400000 with Worker, otherwise the tab freezes (and the timer does not update).
It’s a good and concise example showing both the need for imposing execution cap on the main event loop in browsers and how to calculate huge numbers using bigint libraries.


#16

Their was a bunch of different functions on the page that you can use, not sure which one i should use?
@alper6


#17

@honmanyau Yeah still not understanding that one. I am just using a simple for loop. Now i realized what was happening with my code is that since i was pushing into a array it would stop after 99 and say and “4102 more items.” Now if i do .join(), now it lets me print the number.


#18

Sorry, I can’t help unless you read what I write.


#19

Which part of the page am i looking at?