random percentage that fluctuates javascript/jquery - javascript

So I'm trying to pick a random number based on a percentage. 0-5
0 - 25% (25/100)
1 - 25% (25/100)
2 - 20% (20/100)
3 - 15% (15/100)
4 - 10% (10/100)
5 - 5% (5/100)
But, sometimes one or more of those values will need to be omitted from the picking. So you could encounter something like this
0 - 25% (25/65)
2 - 20% (20/65)
3 - 15% (15/65)
5 - 5% (5/65)
Which means that the percentage has to scale with the other numbers there.
I thought I could use a random function to do something like this
var1 = Math.floor((Math.random() * 100) + 1);
//0 - 25% random(1-25)
//1 - 25% random(26-50)
//2 - 20% random(51-70)
//3 - 15% random(71-85)
//4 - 10% random(86-95)
//5 - 5% random(96-100)
if(var1 <= 25){
var2 = 0;
}else if(var1 <= 50){
var2 = 1;
}else if(var1 <= 70){
var2 = 2;
}else if(var1 <= 85){
var2 = 3;
}else if(var1 <= 95){
var2 = 4;
}else if(var1 <= 100){
var2 = 5;
}else{
// error
}
But I ran into a problem when one or more of the variables (0-5) is omitted. It is possible to setup a bunch of if/else statements but it's not a very practical solution.
Does anybody know a better way I could possibly do this?
Also, if you're unsure of what my question is, please say so. I will try to be more specific and clear on my intentions.

I think, it is exactly what you want. Example
function RangeArray(diffs) {
this.diffs = diffs;
}
// Omit range by index
RangeArray.prototype.omitAt = function(index) {
var arr = this.diffs;
// move value to the next item in array
arr[index + 1] += arr[index];
arr[index] = 0;
}
// Find index of range for value
RangeArray.prototype.indexOf = function(value) {
var arr = this.diffs;
var sum = 0;
for (var index = 0; index < arr.length; ++index) {
sum += arr[index];
if (value < sum) {
return index;
}
}
return -1;
}
// ------- tests ----------
// array of ranges created using your percentage steps
var ranges = new RangeArray([25,25,20,15,10,5]);
// your random values
var values = [1, 26, 51, 70, 86, 99];
// test resutls: indexes of ranges for values
var indexes;
console.log('ranges: 1-25, 26-50, 51-70, 71-85, 86-95, 96-100');
console.log('random values: ' + values.join(', '));
// for your random values indexOf should return 0, 1, 2, 3, 4, 5 accordingly
indexes = values.map(function(x) { return ranges.indexOf(x); });
console.log('test 1 results: ' + indexes.join(', '));
// omit range at index 1 and 4
ranges.omitAt(1);
ranges.omitAt(4);
// for your random values indexOf should return 0, 2, 2, 3, 5, 5 accordingly
indexes = values.map(function(x) { return ranges.indexOf(x); });
console.log('test 2 results: ' + indexes.join(', '));

You store your ranges in an array with a the percentage of each block then you can check them. Be sure that your array sums up to 100.
You can use a simple loop.
var1 = Math.floor((Math.random() * 100) + 1);
var2 =0;
results = [25,25,20,15,10,5];
total = 0;
for (i = 0;i <results.length; i++ ) {
total += results[i];
if (var1 < total) {
var2 = i;
break;
}
}
console.log(var1)
console.log(var2)
example fiddle: http://jsfiddle.net/auo6nc7p/
So in the array above the first item has 25% probablility, the second 25% and so on. You can then remove the element from the array if you do not want them to be picked up.
Is that answering your question ?

Related

Sum of odd numbers until reached limit in Javascript

While I was solving a question saying "add odd numbers from 1 to 20", I coded this:
var i, sum=0;
for (i=2; i<=20; i*2){
sum=sum+i;
}
document.write(sum);
When I launched it through a browser, it did not work. However, when I fixed i*2 into i+=2, it worked.
What am I missing? Am I not able to use *(multiplier) in For Loops?
If you need to add odd numbers from 1 to 20, then you need i+=2 as the third parameter of the for and need to initialize the variable to 1 to get the correct result:
var sum = 0;
for (var i = 1; i <= 20; i += 2) {
sum += i;
}
When you have
i += 2
2 is added to i and the result is stored into i. When you tried
var i, sum=0;
for (i=2; i<=20; i*2){
sum=sum+i;
}
i*2 calculates the value which is twice as big as i, but it will not change the value of i, so this would "work" instead:
var i, sum=0;
for (i=2; i<=20; i*=2){
sum=sum+i;
}
where
i *= 2
not only calculates the value twice as big as i, but stores the result into i as well. However, even though this will run, the result will not be correct, since you are using the wrong formula.
Also, you can calculate the result without using a for:
1 + 2 + ... + n = n * (n + 1) / 2
Assuming that n is pair: and since we know that we are "missing" half the numbers and all the pair numbers are bigger exactly with 1 than the previous impair numbers, we can subtract half of the sequence
n * (n + 1) / 2 - n / 2 = (n * (n + 1) - n) / 2 = (n * (n + 1 - 1)) /
2 = n * n / 2
and now we have exactly the double value of what we need, so the final formula is:
sum = n * n / 4;
Let's make this a function
function getOddSumUpTo(limit) {
if (limit % 2) limit ++;
return limit * limit / 4;
}
and then:
var sum = getOddSumUpTo(20);
Note that we increment limit if it is odd.
The issue is that you're not updating the value of the i in the for loop.
I want add odd numbers from 1 to 20
Then you need to change the initial value of i to 1.
var i, sum = 0;
for (i = 1; i <= 20; i += 2){
sum += i;
}
document.write(sum);
Also, you can find the sum of odd numbers from 1 to 20 by using a formula.
n = 20;
console.log(n % 2 == 0 ? (n * n)/ 4 : ((n + 1) * (n + 1))/4);
You can you just have to do it simillary to what you've written about sum.
You used there i += 2 and not i + 2.
The same way just change i * 2 to i *= 2.
Here is an working example
var i, sum = 0;
for (i = 2; i <= 20; i *= 2) {
console.log(i);
sum += i;
}
document.write(sum);
But a couple of things here.
First of all you wrote
add odd numbers from 1 to 20
and in all your examples you use sum on even numbers.
Secondly, by multiplying you will not achieve your desired goal (as you can see in a snippet above in a console)
So to actually
add odd numbers from 1 to 20
you should do it like this:
var i, sum = 0;
for (i = 1; i <= 20; i += 2) {
console.log(i);
sum += i;
}
document.write(sum);
EDIT
If you want to add even numbers you still can't use multiplying.
Why? Simply because you said yourself that you want a sum of numbers.
So let's say that we start with 2.
If we multiply it by 2 it has the value 4 which is fine.
But now look what happens in the next iteration. Our variable i which has the value 4 is multiplied by 2 and now its new value is 8. So what about 6?
Next iteration multiply 8 by 2 and its new value is 16.
Do you see where this is going?
And when you use i += 2 instead of i *= 2?
So if we start with 2 and than we add 2 its new value is 4.
In next iteration we add 2 to 4 and we have 6.
And so on.
If you want to test it, here is an example with multiplying and adding.
Pay attention to console logs
var i;
console.log("Multiplying");
for (i = 2; i <= 20; i *= 2) {
console.log("i value is: " + i);
}
console.log("Adding");
for (i = 2; i <= 20; i += 2) {
console.log("i value is: " + i);
}
What you are looking is this :
let sum = 0;
for(var i = 2; i <= 20; i += 2){
sum += i;
}
document.write(sum)
Another take on this :
// set to n (what you want). Set to n + 1
var N = 21;
// The main driver code create an array from 0-(N-1) and removes all even nums
let a = Array.apply(null, {length: N}).map(Number.call, _ => +_).filter(_=>_%2)
// console.log the array
console.log(a)
You can use whatever expression in loop header, even this is a valid for loop statement for (;;) which simply runs forever (equivalent to while(true)).
Problem is that you are not updating the i counter in for (i=2; i<=20; i*2) so the i will stays the same throughout the execution of the loop.
If you change it to for (i=2; i<=20; i = i*2) or for (i=2; i<=20; i *=2) then it will work.
It is the same as if you did
let i = 1;
i * 2;
console.log(i);
i = i * 2;
console.log(i);
The first i * 2 doesn't update the i while the second one does.
You can also translate the for loop into while loop to see the error more clearly.
// wrong
let i = 1;
while(i <= 20) {
i * 2;
// do something
}
// right
let i = 1;
while(i <= 20) {
i = i * 2 // or i *= 2
// do something
}
Just a side note, if you wanted to perform sum on more types of sequences efficiently than you could use a generator based approach and write your sum function and describe each type of a sequence with a generator function.
function *generateOdd(start, end) {
for (let i = start; i <= end; i++) {
if (i % 2 === 1) { yield i; }
}
}
function *generateEven(start, end) {
for (let i = start; i <= end; i++) {
if (i % 2 === 0) { yield i; }
}
}
function sumNums(gen, start, end) {
const generator = gen(start, end);
let res = 0;
let item = generator.next();
while (!item.done) {
res += item.value;
item = generator.next();
}
return res;
}
console.log(sumNums(generateOdd, 0, 20));
console.log(sumNums(generateEven, 0, 20));
/* sum of the Odd number using loop */
function sumOfOddNumbers(n){
let sum= 0;
for(let i = 1; i <= n; i++) {
if(i % 2 !== 0){
sum = sum + i;
}
}
return sum;
}
// 567 = 1+3+5+7+9+11+13+15+17+19+21+23+25+27+29+31+33+35+37+39+41+43+45+47
let n = 47;
let sum = sumOfOddNumbers(47);
alert('sumOfOddNumbers(' + n + ') = ' + sum);

Trying to fill 9 spaces with number between 1 and 2 with some rules

I'm trying to fill 9 boxes with numbers, these numbers could be number 1 or number 2, being that number 2 can only be 4 times and number 1 should fill the other 5 times left... i know it's a problem of simple logic but someway I can't reach my goal... look at the piece of code that I have...
<script type="text/javascript">
for (cicloTipo = 1; cicloTipo < 10; cicloTipo++) {
var tipo = Math.floor((Math.random() * 2) + 1);
document.write(tipo);
}
</script>
You can start with an array of the required values, then either shuffle the array or randomly select values from it. Some say Math.random isn't truely random, but it should be good enough.
The following uses splice to select values, so the loop iterates backwards since splicing shortens the source array each time.
function getRandoms(){
for (var seed=[1,1,1,1,1,2,2,2,2], result=[], i=seed.length; i; i--) {
result.push(seed.splice(Math.random() * i | 0, 1)[0]);
}
return result;
}
// Show randomness of result
(function() {
var s = new Array(30).fill('+');
var r;
for (var i=9; i; ){
document.getElementById(--i).textContent = s.join('');
}
var j = 300; // Number of runs
var delay = 20; // Default delay in ms
function display(lag) {
delay = lag || delay;
getRandoms().forEach(function(v, i, rand) {
var el = document.getElementById(i);
if (v == 1) {
el.textContent = el.textContent.slice(0,-1);
// If run out of "+", add some to every line
if (!el.textContent.length) {
for (var k=0; k < 9; k++) {
document.getElementById(k).textContent += '++++++++++';
}
}
} else {
el.textContent += '+';
}
if (i == 0) {
document.getElementById('msg').innerHTML = 'Remaining: ' + j +
'<br>' + 'Values: ' + rand.join('');
}
});
--j;
if (j > 0) {
setTimeout(display, delay);
}
}
display(50);
}());
// Single call
// console.log(getRandoms().join());
<span id="0"></span><br>
<span id="1"></span><br>
<span id="2"></span><br>
<span id="3"></span><br>
<span id="4"></span><br>
<span id="5"></span><br>
<span id="6"></span><br>
<span id="7"></span><br>
<span id="8"></span><br>
<span id="msg"></span>
For fun I've added a display of the distribution. Each line represents a value in the result array from 0 to 8 and starts with a set number of "+" symbols. Each time a 1 is in the related position, a "+" is removed. Each time a 2 is in the position, a "+" is added. Since there are more 1s than 2s, the lines slowly get shorter. When a line gets to zero length, 10 more "+" are added to every line.
The important part is that the lines stay about equivalent lengths and that the same lines aren't longest or shortest after each run. If you think you see a pattern emerging, it must be sustained for at least 100 runs to show a bias.
Here's a solution which ensures that no more than 4 2's are in the chain.
it means that the digits chain can contain from 0 2's to 4 2's and the rest is 1's
// 2s Counter
var c1 = c2 = 0;
for (var cicloTipo = 1; cicloTipo < 10; cicloTipo++) {
var tipo = Math.floor((Math.random() * 2) + 1);
// check if it's a 2 and 4 2s have been encountred
if (tipo == 2) {
if (c2 < 4) {
// increment counter
c2++;
} else {
tipo = 1;
c1++;
}
}
// check if it's a 1 and 5 1s have been encountred
else if (tipo == 1) {
if (c1 < 5) {
// increment counter
c1++;
} else {
tipo = 2;
c2++;
}
}
document.write(tipo);
}
it looks like your criteria forces 4 2's and 5 1's;
i fixed this code to fit this criteria but #Paul Rooney 's suggestion is the best.

IF statements, Arrays and functions - Javascript

For a task I must create a function that generates a number between 1 and 9. This function needs to be called 100 times. Then I need to create a 9 element array that will keep count of the number of times each number appears. My code is below. Currently a number is being generated and the array changes. However the array doesn't change correctly, it changes the wrong index and I don't know why, can anyone help? Any advice on how to call the function 100 times as well would be appreciated. It doesn't matter how it works or looks, I don't need to have a set format.
Thanks in advance!
<script>
function numberGenerate () {
var nmbrGen = Math.floor(Math.random()*8 +1) ;
return nmbrGen;
}
function numberChange () {
document.write(numberGenerate(), "<br>");
var numberArray = [0,0,0,0,0,0,0,0,0];
if (numberGenerate() == 1){
numberArray[0]++;
}
else if (numberGenerate() == 2) {
numberArray[1]++;
}
else if (numberGenerate() == 3) {
numberArray[2]++;
}
else if (numberGenerate() == 4) {
numberArray[3]++;
}
else if (numberGenerate() == 5) {
numberArray[4]++;
}
else if (numberGenerate() == 6) {
numberArray[5]++;
}
else if (numberGenerate() == 7) {
numberArray[6]++;
}
else if (numberGenerate() == 8) {
numberArray[7]++;
}
else {numberArray[8]++;}
document.write(numberArray);
}
</script>
</head>
You call numberGenerate() in each if statement what means that it will generate a new number every if statement. Your code would work if you generate the number one time and compare it, something like that:
var nRand = numberGenerate();
if (nRand ==...
It is needless to say that your code is not well written (to say it in a harmless way). You could just replace all of your if statements with the following:
numberArray[nRand - 1]++;
And to run it 100 times:
for (var i = 0; i < 100; i++) {
var nRand = numberGenerate();
console.log('run ' + (i+1) + ': ' + nRand);
numberArray[nRand - 1]++;
}
You get the wrong index because you are assigning 1 to 0, 2 to 1 and so on. Try this:
var numberArray = [0,0,0,0,0,0,0,0,0,0];
var times = 100; // Run this 100 times
for(var i = 0; i < times; ++i) {
number = numberGenerate();
if(number < numberArray.length) { //Checks, just to be sure
numberArray[number]++;
}
}
PS: with your random function you will get numbers from 1 to 8 both included, but never 9. I'm not sure if that was your intention. This would fix it:
function numberGenerate () {
return Math.floor(Math.random() * 9 + 1);
}
Try this:
function numberGenerate () {
var nmbrGen = Math.floor(Math.random()*9 +1) ;
return nmbrGen;
}
function randomGenerationStats(howManyTimes) {
var stats = {};
for(var i = 0; i < howManyTimes; i++) {
var randomNumber = numberGenerate();
if(stats[randomNumber]) {
++stats[randomNumber];
} else {
stats[randomNumber] = 1;
}
}
return stats;
}
console.log(randomGenerationStats(100));
Prints:
Object {1: 14, 2: 13, 3: 11, 4: 8, 5: 12, 6: 18, 7: 6, 8: 5, 9: 14}
The output in console will be object whch keys are numbers from 1-9 with values how many times they occurred.
Hm.. I'll ad my answer
Your Math.random is false, check out : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Math/random
A for loop will let you repeat instruction for a counted number of time. See : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for (You can also check a while loop if you don't know the number of occurence you gonna pass)
Using this approch, numberArray[0] will give the occurence of 1.
You don't need to call a function which call Math.random, it's pointless if you aren't doing it in a dynamic way.
Hope this help, even if some answer do the tricks.
var numberArray = [0,0,0,0,0,0,0,0,0];
var nmbrGen;
for(var i=0; i<100; i++) { // From 0 to 99, so 100 time.
nmbrGen = Math.floor(Math.random() * 9 + 1); // 9 + 1 = (Max - Min + 1 + Min)
console.log("Generated : "+nmbrGen);
numberArray[nmbrGen-1]++;
}
Firstly, there's a bug in your numberGenerate function. It will only produce numbers from 1 to 8. What you need to do is change the corresponding line to Math.floor(9 * Math.random() + 1).
Secondly, every successive call to numberGenerate creates a new random number. Call the function once and store the value once per loop iteration. So, you must insert a line like var rand = numberGenerate(); at the top of the numberChange function, and replace every call to numberGenerate following with rand.
Thirdly, notice a pattern with the number in your if conditions and the statement underneath. The number in the condition is from 0-8, and the number in the statement beneath is one more than it. You can simply all of that into one statement after realizing this pattern by replacing all the if statements with this single line numberArray[rand - 1]++.
And lastly, you forgot the most important part! You need to iterate 100 times! Include a for loop surrounding the code in the numberChange function.
After you've made all these changes, the code should resemble this.
function numberGenerate () {
return Math.floor(9 * Math.random() + 1);
}
function numberChange () {
var numberArray = [0, 0, 0, 0, 0, 0, 0, 0, 0];
for(var i = 0; i < 100; i++) {
var rand = numberGenerate();
document.write(rand, "<br>");
numberArray[rand - 1]++;
}
document.write(numberArray);
}
If I understood you right, you want to count the occurrences of these 9 random numbers?
It is easier if you use an associative array (dictionary) for this.
You have a function that generates random numbers between 1 and 9.
I have created an associative array with 9 keys (from 1 to 9), and set the respective value to 0. That value is the "occurrence counter".
Then we loop through 100 times, as you requested and change the counter of that value. Something like this:
function numberChange() {
// read this array as "value 1 has 0 occurrences, value 2 has 0 occurrences, etc."
var numberArray = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9:0 }
for (var i = 0; i < 100; i++) {
// generate 100 random numbers and add the relative counter value.
var newRandomNumber = numberGenerate();
numberArray[newRandomNumber]++;
}
// loop through all keys and display the respective occurrence counter value.
for (var key in numberArray) {
console.log("Number: " + key + " Occurrences: " + numberArray[key]);
}
}
function numberGenerate() {
var nmbrGen = Math.floor(Math.random() * 9 + 1);
return nmbrGen;
}

How to get percent from an binary int, with every bit representing x percent?

I have an binary bitmap with 10bits. Every bit represents 10%. Is there any simple math function to get the sum of percent from the bitmap?
Sample
0000000000 = 0%
0000000001 = 10%
1000000000 = 10%
0000100000 = 10%
1000000001 = 20%
0000000011 = 20%
0000110000 = 20%
0010000010 = 20%
1010000010 = 30%
Be aware this is just an example of how the bits are activated. The number i have actually is an int such as 0,1 to 1023.
You don't have to use a loop. You don't have to do math. Just do it like this:
var number = 1000100010;
alert(number.toString().split("1").length - 1);
//A little more deep:
var number2 = 1100100000;
alert((number2.toString().split("1").length - 1) * 10 + "%");
Use a loop:
function count_1bits(n, bitsize) {
var count = 0;
for (var i = 0; i < bitsize; i++) {
count += (n & 1); // test low-order bit
n >>= 1; // shift number down 1 bit
}
return count;
}
var pct = count_1bits(bitmap, 10)*100;
You can count the bits with a function like this, then just multiply by 10 to get it as percent:
function countBits(n, cnt) {
if (cnt == 1) return n & 1;
var half = Math.floor(cnt / 2);
return countBits(n >> half, cnt - half) + countBits(n, half);
}
n = 1023;
document.write(countBits(n, 10) * 10 + '%');
Try doing something like
x = '0000100011';
function binTopre(x) {
c = (x.match(/1/g)||[]).length;
return (c*10) + '%';
}
console.log(binTopre(x));//30%

Skewed Number Generator

I have a simple implementation question.
Here is the random number function I have, and returns a random number from a given range, inclusive.
function randomNum(low, high){
return Math.floor(Math.random() * (high - low + 1)) + low;
}
However, I would like to have 50% chance of getting the high number, and 25% for everything else..
for example:
randomNum(1, 3)
'3' would have a 50% chance of getting a hit, while '1' and '2' will both have a hit percentage of 25%.
I'm not too sure as to what changes I need to make to my function...tips would be great, Thanks
function randomNum(low, high){
return Math.random() > 0.5 ?
high :
Math.floor(Math.random() * (high - low)) + low;
}
In a generic manner; I suppose you're after a weighted random number generator:
function weightedRandomNumber(weights) {
var sum = 0;
for (var w in weights) {
w = weights[w];
sum += w.weight;
}
var rand = Math.random() * sum;
for (var w in weights) {
w = weights[w];
if (rand < w.weight) {
return w.value;
}
rand -= w.weight;
}
return weights[weights.length - 1].value;
}
Test:
var config = [
{ weight: 25, value: 1 },
{ weight: 25, value: 2 },
{ weight: 50, value: 3 }
];
var test = { 1: 0, 2: 0, 3: 0 }, max = 10000;
for (var i = 1; i < max; i += 1) {
test[weightedRandomNumber(config).toString()] += 1;
}
alert('From ' + max + ' rounds; results: ' + JSON.stringify(test));
Make if else condition
If it is 3 its ok or else if it is not 3 then again make a random number between 1 and 2;
Hence the 3 will get 50% chances where as 1,2 will get 25% chances
There are two approaches that you can use. (1) You can have array of value and random the index of value to get. If you want certain number to have higher chance, just put it more. For example:
var arr = [1, 2, 3, 3];
return arr[Math.floor(Math.random() * arr.length)];
(2) Second approach is doing the array shuffling.
var arr[1, 2, 3, 3];
shuffle(arr);
return arr[0];
This should work:
function randomNum(low, high){
var mid = (low + high)/2;
var randomn = Math.floor(Math.random() * (high - low + 1)) + low;
if(randomn > mid)
return randomn ;
else
return Math.floor(Math.random() * (high - low + 1)) + low;
}
here you go. high will have 50% chance, the rest will split the other 50% equally
function randomNum(low, high)
{
var myarry = []
for(var i=0;i<(high-low);i++) { myarry.push(low+i) } ; //var myarry=[low, low+1, ....,high-1] excludes high
console.log(myarry)
var magic=Math.random();
var index=Math.round(magic*(high-low)); // Gaurantee the chance is split between the elements of the array
return Math.round(magic)==1?high:myarry[index] // Guaranteed 50% chance for high either 0 or 1, the rest will split the chance
}

Categories