0

I have a long loop that takes maybe 10 mins or more, and I want to set always a new time to avoid it to continue. But it dosen't works.

    function problem3(){
                var img = document.getElementById('p_3');
                img.style.display = img.style.display === 'block' ? 'none' : 'block';
                var number=600851475143;
                var t = new Date();
                for(var i=3;i*i<=number;i+=2){
                    if(isPrime(i) && number%i==0){
                        var maxPrime = i;
                    }
                    setInterval(function(){time(t)},5000);
                }
                document.getElementById("p3").innerHTML = 'Il più grande divisiore primo di <span>'+number+"</span> è  <span>" + maxPrime+"</span>"; 
    }
function time(t){
            return console.log(Date() - t);
        }

If I put console.log(Date() - t);in the problem3() function it works, but I can't do Date()-t every 5 seconds, something like setInterval(Date()-t,5000)

4
  • 1
    Are you trying to get the maximum prime factor? Then when you find a prime factor, divide the number by that. Commented Nov 4, 2016 at 15:26
  • Yes I did : if(isPrime(i) && number%i==0) by mod , but the broblem is in JS, becouse the chrome browser charshes always, so I want to give it more time ..UPDATE: Ok I understend what did you want to say me Commented Nov 4, 2016 at 15:28
  • 1
    I mean number /= i, until number%i != 0. It will make the loop shorter if number has various prime factors. Commented Nov 4, 2016 at 15:30
  • Yes I understood man. But what about this EULER 551 PROBLEM (without math tricks)... I need a method to avoid browser to work more times Commented Nov 4, 2016 at 15:32

3 Answers 3

2

This is a case where you might consider using the workers API. Instead of freezing the browser, let the job be done in the background and call back to the main thread when it's done.

https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API

Sign up to request clarification or add additional context in comments.

2 Comments

Yes, but I need a general solution. I mean that Web workers can't interact with the DOM
It's on purpose. When the result comes up, the worker passes a message back to the UI thread, and the latter updates the DOM. It's not more complicated than intercepting a click-event, and avoids much of the mess that would come if sharing unsynchronized data between threads.
1

JavaScript is not multithreaded. So we think of setInterval() as running a piece of code every n ms (5000 in your example). But that's not quite true. If there's already script running when the interval elapses, the best that can happen is the bit of code gets added to a queue to be executed - but nothing from that queue is going to run until the already-running script finishes.

So in rough terms that's why it's not working, but what to do? Well, if you want anything to happen before problem3() returns, then problem3() is going to have to make it happen in a synchronous way.

For example, you could create a lastOutputTime variable, initialize it to the current time, and on each iteration through the for loop compare the current time to the stored value. If 5 seconds have passed, output to console and update lastOutputTime.

1 Comment

Perfect I understand ! Anyway I found the bug into my code function, here : time(t){ return console.log(Date() - t); } I forget the new before Date(),so now time(t){ return console.log(new Date() - t); } works
1

Your algorithm should be improved to something like this:

function maxPrimeFactor(number) {
  if (number == 0 || !Number.isInteger(number) ||
      number > Number.MAX_SAFE_INTEGER) return NaN;
  number = Math.abs(number);
  while(number % 2 == 0) number /= 2;
  for (var i = 3; i * i <= number; i += 2) {
    while(number % i == 0) number /= i;
  }
  return number;
}
var number = 600851475143;
console.log('maxPrimeFactor(' + number + ') == ' + maxPrimeFactor(number));

If for some numbers you need too much time, then break the loop into smaller chunks and asynchronize. But never use setInterval for this, and especially never use setInterval inside a long loop. setInterval schedules some task to run every n milliseconds, so if you use it in a loop, after i iterations, the task will run i every n milliseconds! And setInterval is so problematic because it can freeze the browser if the task takes more than n milliseconds. You should use setTimeout instead.

However, this would be useless in this case. The algorithm above can detect that 304250263527209 (15 digits) is a prime almost instantly. Given that the maximum safe integer is 9007199254740991 (16 digits), I don't think you will have problems for any number.

If you say the algorithm takes so long, it may be because you are trying it with bigger numbers. But be aware JS numbers are 64-bit floating point numbers, and thus integers can't be represented accurately above Number.MAX_SAFE_INTEGER. You will get a wrong result anyways, so do not even try to calculate that.

In the case of the Project Euler #551, a brute-force approach would be

function sumOfDigits(n) {
  var sum = 0;
  while(n != 0) {
    sum += n % 10;
    n = Math.floor(n/10);
  }
  return sum;
}
function sumDigitsSeq(n) {
  return new Promise(function(resolve) {
    var i = 1;
    var chunkSize = 1e5;
    var sum = 1;
    (function chunk() {
      chunkSize = Math.min(chunkSize, n-i);
      for (var j=0; j<chunkSize; ++j, ++i) {
        sum += sumOfDigits(sum);
      }
      if (i >= n) return resolve(sum);
      console.log('Please wait. sumDigitsSeq(' + i + ') == ' + sum);
      setTimeout(chunk, 60);
    })();
  });
}
var number = 1e6;
sumDigitsSeq(number).then(function(result) {
  console.log('Done! sumDigitsSeq(' + number + ') == ' + result);
});

Of course brute-force is not the appropriate way to solve the problem.

3 Comments

That's a really good solution for the algorithm but I want just to handle the thread, becouse how can I do this EULER PROBLEM .... var max = 1e+15; var sum = new BigNumber(1); for(var i=1;i<max;i++){ sum = sum.plus(scomponi(sum,0));} scomponi split number in digits and sum them...
@Teshtek Anyways, I don't think you are supposed to use brute force to solve these euler problems. You are probably supposed to use math to find an easy formula.
Yes there are math tricks, but I want just to learn how to handle long loops or big tasks, that takes a lot of time, in js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.