I'm having problems on Firefox 15 and Chrome 21 with the following code:
setInterval(function () { console.log('test') }, 300000000000)
On both browsers, the function is run right away repeats very quickly. Sure, that's a big number (representing about 10 years from now), but I wouldn't expect it to be treated as a tiny or negative number. I haven't seen a maximum allowed delay in any documentation. Does anyone know if there's a standard max, or if this is just the browsers being funny?
The interval is stored in a signed 32-bit int (in the tested implementation: V8 in Google Chrome), so the behavior you're seeing is the result of the interval overflowing to a negative number (in which case it behaves as if the interval was 0). Thus, the maximum interval that you can use is 2**31 - 1.
Here's how I determined that this was the case:
setInterval(function(){console.log("hi");}, Math.pow(2,31));
Behaves like the interval is 0.
setInterval(function(){console.log("hi");}, Math.pow(2,31) - 1);
Doesn't fire in the time I was willing to wait.
setInterval(function(){console.log("hi");}, Math.pow(2,33) + 1000);
Behaves like the interval is 1000 (one second). Here, the 2**33 doesn't affect the first 32 bits, so we get just 1000.
The highest possible interval, 2**31-1ms is a little shy of 25 days, so more than enough for anything reasonable.
I can't find any documentation at the moment, but I wouldn't be surprised if the timer value had to fit in a 32-bit signed integer.
I think that the maximum delay is 231-1 which is 2,147,483,647ms. The maximum value of a signed 32 bit integer in ms. If it would be unsigned it would be 232-1 = 4,294,967,295.
Max is 2,147,483,647 (231-1)
Be careful that if you make the number bigger than that, it will run immediately (Imaging that you put a negative value, so the browser will run infinitely loop)
setInterval(()=>console.log('n'),2147483647)
31
setInterval(()=>console.log('y'),2147483648)
38
(1588) y
If you need an interval larger than 2,147,483,647 here's an example in TypeScript that will allow you to set an interval for a max of 458,496,310,632,933,156,516.92 days:
Obviously, I have not tested that this works for that long :D.
export const setLongInterval = (callback: any, timeout: number, ...args: any): Timeout => {
let count = 0;
const MAX_32_BIT_SIGNED = 2147483647;
const maxIterations = timeout / MAX_32_BIT_SIGNED;
const onInterval = () => {
++count;
if (count > maxIterations) {
count = 0;
callback(args);
}
};
return setInterval(onInterval, Math.min(timeout, MAX_32_BIT_SIGNED));
};
export const setLongTimeout = (callback: any, timeout: number, ...args: any): Timeout => {
let count = 0;
let handle: Timeout;
const MAX_32_BIT_SIGNED = 2147483647;
const maxIterations = timeout / MAX_32_BIT_SIGNED;
const onInterval = () => {
++count;
if (count > maxIterations) {
count = 0;
clearInterval(handle);
callback(args);
}
};
handle = setInterval(onInterval, Math.min(timeout, MAX_32_BIT_SIGNED));
return handle;
};
The delay argument is converted to a signed 32-bit integer. This effectively limits delay to 2147483647 ms, since it's specified as a signed integer in the IDL.
It is mentioned in the documentation
Related
I want to implement a method that returns true with a probability of n/m and returns false with a probability of (m-n)/m.
For example, I want to get true with a probability of 7/10000.
To achieve this, I first get a random integer n that is under 10000 from the function getRandomIntUnderN. Then, I judge whether n is smaller than (7+1), if it is, I return true, false if not.
I have an implementation below:
// 0 is included while n is not
const getRandomIntUnderN = (n) => {
const rn = Math.random() * n
return Math.trunc(rn)
}
// the opportunity of a truthy return value is n/m
const goAtChance = (n, m) => {
return getRandomIntUnderN(m) < n
}
// a opportunity of 7‰ to return true
console.log(goAtChance(7, 10000))
My question is: is it okay that I just judge whether n is under (7+1) to make a perfect probability as expected?
On one hand, numbers from 1 to 7 are not distributed discretely enough in the range from 1 to 10000: it seems there will be a bias that makes it unlikely to return a truthy value.
On the other hand, since I can get a purely random number from getRandomIntUnderN, the chance will not be affected by which numbers I choose to determine the return value. It can be [1,2,3,4,5,6,7], [21,22,23,24,25,26,27], [23,55,3,66,762,92,123] or whatever under 10000.
So, which opinion is right?
Then, I judge whether n is smaller than (7+1), if it is, return true, false if not.
This is not how you implemented it. Your code checks that n is less than 7, which is the correct way to do it.
it seems there will be a bias that makes it unlikely to return a truthy value.
Where does that statement come from? Surely you can test this premise... and see how likely it is.
the chance will not be affected by which numbers did I choose to determine the return value
This is true.
How to test
You can easily test what the distribution is of your implementation. You can call the function repeatedly and keep a record of the results you get, and see how that evolves over time. In statistics you get more reliable results the greater the size of your sample is.
Here is a snippet that keeps executing the goAtChance function and records the total number of calls and the number of true results. Every 10 milliseconds the results are updated on the page, including the ratio of the number of true over the total number. This ratio should over time converge to 0.0007 if all is well.
const getRandomIntUnderN = (n) => Math.floor(Math.random() * n);
const goAtChance = (n, m) => getRandomIntUnderN(m) < n;
let [outTotal, outHits, outRatio] = document.querySelectorAll("span");
let hits = 0; // Number of results that are true
let total = 0; // Total number of results
requestAnimationFrame(function loop() {
let deadline = performance.now() + 10;
do {
hits += goAtChance(7, 10000); // boolean coerces to 0 or 1
total++;
} while (performance.now() < deadline);
// Show the accumulated results
outTotal.textContent = total;
outHits.textContent = hits;
outRatio.textContent = (hits / total).toFixed(8);
requestAnimationFrame(loop); // Allow screen to update and then continue
});
Samples: <span></span><br>
Hits: <span></span><br>
Ratio: <span></span>
I read some threads on the site about getting percentages of running a function, but none of them guide me how to get a specific decimal percentage of running a function.
I tried something like:
Math.floor(Math.random() * 100) + 1 + '%'
However it doesn't return decimals.
What i'd like is for it to let's say, have a 0.5% / 100% chance of running console.log("0.5%"), is there any way to do this? Thank you very much!
Math.random() returns a random number between 0 and 1.
A percentage is just a fraction out of 100. Divide by 100 to get a number between 0 and 1.
So, to get a block of code that runs a certain percentage of the time, take the desired percentage, divide it by 100, and run the code if a random number is less than it.
if( Math.random() < 0.5/100) {
/* code that runs 0.5% of the time */
}
Here is what you are asking for.
The percentageFromRandom is explained in my comment above.
The runWithProbability function calls a given function with a certain probability, when this function is called.
The logWithProbability uses the runWithProbability function, but with the custom console.log functionality as your answer question for.
The init function shows an example of usage of the function, by running it 30 times with 30 random probability. In most cases it would log the larger %'s as they are more likely to have the console.log function be called.
//convert the random value into human readable percentage
function percentageFromRandom(value, fractionalDigits = 2){
return (value*100).toFixed(fractionalDigits)+'%';
}
//take a function and probability of running it
//if the probability is met, call the function.
function runWithProbability(fn, probability){
if(probability >= 1 || Math.random() < probability){
return fn(probability);
}
return false;
}
//make a console log with a certain probability,
//log the percentage probability if called
function logWithProbability(probability){
runWithProbability(()=>
console.log(percentageFromRandom(probability))
, probability);
}
// See console logs and their probability as
// a percentage of running.
const init = () => {
for(let i = 0; i < 30; i++){
logWithProbability(Math.random());
}
}
init();
The issue with the Math.floor(Math.random()) example is that Math.floor() removes all of the fractional values of a number. To get precision to a certain fixed point, multiply by the maximum whole number wanted, then adjust to a fixed decimal.
for (var i = 0; i < 10; i++) {
var num = 10 * Math.random(); // Max 10.000...
console.log(num, num.toFixed(1) + '%') // Fix (and round) the first decimal
}
Interval isn't running once per millisecond. The final number only gets to 459 before stopping. Less if there is more than just a line on the interval. On here it doesn't even move through the first thousand. What I want is for it to run once per second to let me know how far an interval is done. So if testNum is at 30, then I know that it's 97% of the way done (2970/3000).
let testNum = 3000
let testInt = setInterval(() => {
testNum--
}, 1)
let testTimeout = setTimeout(() => {
clearInterval(testInt)
console.log('Final Number: ' + testNum)
}, 3000)
From https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval#Parameters:
delay
The time, in milliseconds (thousandths of a second), the timer should delay in between executions of the specified function or code. If this parameter is less than 10, a value of 10 is used.
Have a look at Reasons for delays longer than specified as well.
In order to not chock the listener I want to play a wave but the volume should not be played at 100% ratio from early, it should go from 0% to 100% in duration of 2secondes for instance.
I tought of a setTimeout and I increase the gain by the time, but I don't know if is there any other better approch
var source = aCtx.createBufferSource();
source.buffer = buf;
var gainNode = aCtx.createGain();
gainNode.gain.value = 0
source.connect(gainNode);
gainNode.connect(aCtx.destination);
source.start(0);
setTimeout(function() {
gainNode.gain.value = 0.5
}, 1000)
setTimeout(function() {
gainNode.gain.value = 1
}, 2000)
The Web Audio API provides a library function for this.
AudioParam.linearRampToValueAtTime(value, endTime)
value
A floating point number representing the value the AudioParam will ramp to by the given time.
endTime
A double representing the exact time (in seconds) after the ramping starts that the changing of the value will stop.
So in your case use
gainNode.gain.linearRampToValueAtTime(0, 0)
gainNode.gain.linearRampToValueAtTime(1, 2)
Make it dynamic by simply using some kind of lerp function, there are many out there. The basic idea is that you get a value being interpolated between two of your starting values.
Example:
value 1 = 5
value 2 = 1
interpolation amount = 0.4 (40%)
then the result should be exactly 2.6
said function might just look like this
Math.lerp = function (value1, value2, amount) {
amount = amount < 0 ? 0 : amount;
amount = amount > 1 ? 1 : amount;
return value1 + (value2 - value1) * amount;
};
In your specific scenario you would take the min and max volume as the both values and then regulate the amount using the time that has passed. Probably with some async function call back to this function.
hope i could help.
While playing around with random numbers in JavaScript I discovered a surprising bug, presumably in the V8 JavaScript engine in Google Chrome. Consider:
// Generate a random number [1,5].
var rand5 = function() {
return parseInt(Math.random() * 5) + 1;
};
// Return a sample distribution over MAX times.
var testRand5 = function(dist, max) {
if (!dist) { dist = {}; }
if (!max) { max = 5000000; }
for (var i=0; i<max; i++) {
var r = rand5();
dist[r] = (dist[r] || 0) + 1;
}
return dist;
};
Now when I run testRand5() I get the following results (of course, differing slightly with each run, you might need to set "max" to a higher value to reveal the bug):
var d = testRand5();
d = {
1: 1002797,
2: 998803,
3: 999541,
4: 1000851,
5: 998007,
10: 1 // XXX: Math.random() returned 4.5?!
}
Interestingly, I see comparable results in node.js, leading me to believe it's not specific to Chrome. Sometimes there are different or multiple mystery values (7, 9, etc).
Can anyone explain why I might be getting the results I see? I'm guessing it has something to do with using parseInt (instead of Math.floor()) but I'm still not sure why it could happen.
The edge case occurs when you happen to generate a very small number, expressed with an exponent, like this for example 9.546056389808655e-8.
Combined with parseInt, which interprets the argument as a string, hell breaks loose. And as suggested before me, it can be solved using Math.floor.
Try it yourself with this piece of code:
var test = 9.546056389808655e-8;
console.log(test); // prints 9.546056389808655e-8
console.log(parseInt(test)); // prints 9 - oh noes!
console.log(Math.floor(test)) // prints 0 - this is better
Of course, it's a parseInt() gotcha. It converts its argument to a string first, and that can force scientific notation which will cause parseInt to do something like this:
var x = 0.000000004;
(x).toString(); // => "4e-9"
parseInt(x); // => 4
Silly me...
I would suggest changing your random number function to this:
var rand5 = function() {
return(Math.floor(Math.random() * 5) + 1);
};
This will reliably generate an integer value between 1 and 5 inclusive.
You can see your test function in action here: http://jsfiddle.net/jfriend00/FCzjF/.
In this case, parseInt isn't the best choice because it's going to convert your float to a string which can be a number of different formats (including scientific notation) and then try to parse an integer out of it. Much better to just operate on the float directly with Math.floor().