I want the number to stop when the variable num reaches a whole number. The pausing works correctly, but it goes up by 0.01 then pauses. The statement is ran every frame (via requestAnimationFrame).
if (Math.floor(num * 100) / 100 == Math.floor(num) && pause < 50) {
pause += 1;
} else {
pause = 0;
num += 0.01;
}
The complete code block is on GitHub:
https://github.com/BootLegAidan/Geometrical-Thing/blob/master/Update.js
The issue appears to be your Math.floor(num * 100 ) / 100 == Math.floor(num) condition evaluating to true even if num has a very small decimal value -- such as 1.000000007.
You can avoid that issue by comparing num to its rounded value directly:
if (num == Math.floor(num) && pause < 50) {
Compared that way, unless num is a whole number, the condition won't be true.
Related
I am trying to get my countdown to stop at zero however it resets rather than stops.
I've added a conditional statement at the end of the runTimer function but nothing happens. It just resets.
I'm going off of an exercise where it counts up. I'm modifying it a bit and having it countdown.
function runTimer() {
let currentTime = leadingZero(timer[1]) + ":" + leadingZero(timer[2]);
theTimer.innerHTML = currentTime;
timer[3]--;
timer[0] = Math.floor((timer[3]/100)/60); //minutes
timer[1] = Math.floor((timer[3]/100) - (timer[0] * 60)); //seconds
timer[2] = Math.floor(timer[3] - (timer[1] * 100) - (timer[0] * 6000)); //hundredths
if (currentTime = 0) {
clearInterval(interval);
}
}
I expected it to stop at zero but it just resets back to 59:00... and I want it to stop at 00:00.
The problem is this part:
if (currentTime = 0)
Since you're checking if the value is 0, you don't want to assign a value of 0, instead you want to compare currentTime with 0. This is done with the === operator. So to summarize:
= is to assign a value to a variable. ( left is variable and right is the assignment)
== or === is to compare the two values.(Difference between == and === in JavaScript)
Your line should be:
if (currentTime == 0)
Hope it helped. :)
Two points.
1) As already mentioned, your if clause will not work because you are using "=" (a single equal sign). A single equal sign in JavaScript does assign values, not compare values. You however want to compare values and need to use double or triple equals.
2) Even if you change that, currentTime will probably never evaluate to zero, since you have assigned a string to currentTime before. So even if currentTime is "00:00", the string will not evaluate to 0 (see image)
I guess you more want to do something like this:
if (timer[2] === 0 && timer [1] === 0 && timer[0] === 0) {
clearInterval(interval);
}
Or most probably this will suffice:
if (timer[3] <= 0) {
clearInterval(interval);
}
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)
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
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.
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.
When trying out the code below as a solution for the Euler Project problem 5. The problem is find the smallest number equally divisible by all numbers from 1 to 20. Every time it is run it presents "Unresponsive Script" window and I need to physically stop the script from running. It seems like something is causing it to hang but I can't quite figure out what. The alert window seems to point to an error with the line the while() starts on but I can't see anything wrong with it.If it looks like it should work I'd appreciate anyone trying it on their machine to see if it works. That way I can eliminate it as a local problem. All suggestions welcome.
var divisible = false;
var n = 2520; // first number divisible by all numbers 1-10
while(divisible === false){ // something wrong here??
n += 2520;
for(var i = 11; i < n; i++) {
if(i % n !== 0){
break;
}
if(i === 20) {
divisible === true;
}
}
}
if(divisible === true){
return console.log("Answer: " +i);
}
Because you break out of your for loop if i % n isn't 0 the very first time. And you never set divisible to true - divisible === true isn't the same as divisible = true
There are several errors in the original code, some pointed out in the answer above. To make it work several fixes are needed.
First, the boolean divisible must be correctly set to true using the assignment operator = inside the for loop instead of === which is used only to check if two values are strictly of the same type AND value.
The next problem is the conditional part of the for loop i < n should be i < 20 because the loop is checking if numbers between 11 and 20 divide evenly into n.The last fix to make the code run correctly is the order of the condition if the first if statement which should read if(n % i !== 0) and not if(i % n !== 0). I think it might be this specific part that caused the code to crash and generate the "Unresponsive Script" alert in the browser.
Here is the fixed code.
var divisible = false;
var n = 2520; // smallest number divisible by all numbers 1-10
while(divisible === false){
n += 2520; // increment n on each new pass
// loop numbers between 11 and 20
for(var i = 11; i <= 20; i++) {
if(n % i !== 0){ // check if i divides equally into n
// if not break out of current loop and start again
break;
}
// if i reaches 20 then all the numbers divided equally into n
if(i === 20) {
// set value of divisible to true to cancel while loop
divisible = true;
}
}
}
// return the last value of n
return console.log("Answer: " +n);
I have a homework question I've been having trouble with.
I have to write a function that checks if every alternate digit in a given number has the same parity. For example, both 1 2 3 3 and 2 1 3 3 are valid, but 1324 is not. I have no idea how to go about doing this, though. How do I keep track of previous digits, for one thing? Any help would be much appreciated.
Edit: My efforts so far:
Any number < 100 clearly isn't acceptable (right?) since 'every alternate digit' doesn't really make sense here. For 3-digit numbers, this should work:
function validate(n) {
var i, copy, l = [0, 0];
if (isNaN(n) || (n < 100)) {
return false;
} else {
copy = Math.round(n);
for (i = copy.toString().length; i--; n = Math.floor(n / 10)) {
l[0] = l[1];
l[1] = l[2];
l[2] = n % 10;
}
if ((l[0] % 2) == (l[2] % 2)) return true;
}
}
Edit[2]: Thanks for your help, everybody. I've managed to get an honest-to-goodness real (I think) working function based on Salix alba's first suggestion to save the parities of the first and second digits. The loops run backward over the digits.
For now, this (along with making a couple of minor edits to save the parities of the last and second-last digits instead as Salix alba said, which would make the parity = lines simpler) is my solution:
function validate(n) {
var copy, len, parity, broke = 0, i = 2;
if (!isNaN(n) || (n >= 100)) {
n = Math.round(n);
len = n.toString().length;
copy = n; // save
parity = Math.floor(n / Math.pow(10, len - 1)) % 2;
n = Math.floor(n / 10);
while (i < len) {
if (parity != ((n % 10) % 2)) {
broke++;
break;
}
i += 2;
n = Math.floor(n / 100);
}
n = copy; // restore
i = 1;
parity = (Math.floor(n / Math.pow(10, len - 2)) % 10) % 2;
while (i < len) {
if (parity != ((n % 10) % 2)) {
broke++;
break;
}
i += 2;
n = Math.floor(n / 100);
}
if (broke != 2) return true;
}
return false;
}
It's a horrible mess, of course. I would really, really appreciate any ideas for make this more efficient, easier to read, etc.
(Also going to try to write another function with jing3142's method of iterating with a flag, which might make the loops simpler.)
You are working along the right lines but there are a number of issues. You code only works for three digits since your check if ((l[0] % 2) == (l[2] % 2)) return true; only operates once at the end of the loop.
So you need to set a flag, say valid and put valid = valid && ((l[0] % 2) == (l[2] % 2)) inside the loop.
The loop will now fail because the first use of l[2] in l[1] = l[2] will be undefined since it has not been defined.
If you correct these then you will need to check whether there are an even or odd number of digits else it will fail for an odd number of digits.
Also you imply in your comment that you are not to use strings and in practice you do even if it is only to find the length.
There is another way.
The clues in your working out is that if n<100 then no check can be done, and that you need to reduce n be a factor of 10 each time through n = Math.floor(n / 10) while you loop.
Rather than give you a solution as you ask for advice not a solution here is a hint.
given that n>100 to start with and if U is unit digit, T tens digit and H hundreds digit of n then while n>100 how do you calculate U and H, how do you then set the valid flag, in the loop?
EDIT Looks like you still need some help
Algorithm not code
function validate(n) {
if(n<100) return not applicable
valid=true
while(n>100) {
U=n % 10
H=Floor(n /100) % 10
valid = valid && ((U % 2) == (H % 2))
n=Floor(n/10)
}
return valid
}
function pow(n,to){
if(to == 0 ) return 1;
h = pow(n,to/2);
return h*h* ((to % 2) == 0 ? 1 : n);
}
Why does this code return infinity for power different than 0?
The recursion in your function will never stop. That is because to / 2 will never be 0 when it's greater than 0. to will have these values throughout the recursion when you call it with an initial value of 10:
10 -> 5 -> 2.5 -> 1.25 -> 0.625...
You can use Math.floor() to cut off the part of a float after the decimal point. This is the function how you want it to be:
function pow(n, to) {
if (to == 0) {
return 1;
}
var h = pow(n, Math.floor(to / 2));
return h * h * ((to % 2) == 0 ? 1 : n);
}
You have infinite recursion. Meaning your function is calling itself and there is no condition to stop it from doing so. So it's calling itself forever until the javascript engine stops it. Put a console log in your function and watch it in the console.