Get random number based on probability [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I was wondering to get a random number with two decimal places based on probability for example:
40% to get number from 1-10
20% to get number from 11-20
30% to get number from 21-30
10% to get number from 31-35

function Prob(){
var rnd = Math.random(),
rnd2 = Math.random();
if(rnd<0.4) return (1 + Math.floor(1000 * rnd2)/100);
else if(rnd<0.6) return (11 + Math.floor(1000 * rnd2)/100);
else if(rnd<0.9) return (21 + Math.floor(1000 * rnd2)/100);
else return (31 + Math.floor(500 * rnd2)/100);
}
You need two random numbers, so I calculate them at the start. I then use the if-else loops to cycle through your 40%, 20%, 30% and 10% (adding them up as I go). Note: Math.random returns a number between 0 and 1. Then for each catagory I use the SECOND random number to get in the range you have said - floor it to make sure it is an integer and add the starting number of each range. Note: the range of your last one is just 5.
I should explain, you must use two random numbers, otherwise the range of the second number would be dependent on which category you are in.
I have to do the 1000 * rnd2 in the floor and then divide by 100 outside to get the 2 decimal place you ask for.

Rewind's solution is great and specifically tailored to OP's quesiton. A more re-usable solution might be:
function getNumber(probabilities){
var rnd = Math.random();
var total = 0;
var hit;
for(var i = 0; i < probabilities.length; i++){
if(rnd > total && rnd < total + probabilities[i][0]){
hit = probabilities[i]
}
total += probabilities[i][0];
}
return Number((hit[1] + (Math.random() * (hit[2] - hit[1]))).toFixed(2));
}
var number = getNumber(
[
//chance, min, max
[0.4, 1, 10],
[0.2,11,20],
[0.3,21,30],
[0.1,31,35]
]
);
console.log(number);
The function will take an array with the probabilities, for each probability you specify the chance, the minimum value for that chance, the maximum value for that chance. It will return a number with two decimals.
https://jsfiddle.net/x237w5gv/

I guess this
var get1120 = _ => ~~(Math.random()*10)+11,
get2130 = _ => ~~(Math.random()*10)+21,
get3135 = _ => ~~(Math.random()*5)+31,
a = [get3135,get1120,get1120,get2130,get2130,get2130],
fun;
result = (fun = a[~~(Math.random()*10)]) ? fun() : ~~(Math.random()*10)+1;
console.log(result);
might do it;

Related

Create random number different from the numbers inside an array [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have an array for example [2,8,5,6], and I want to generate a random number different from the numbers that are inside the array, and that this number is not greater than 100.
Many thanks friends
Using Set to avoid collisions
arr = [2, 8, 5, 6]
getRandom = (exclude, min = 0, max = 100) => {
let rand = Math.random() * 100 | 0
while (exclude.has(rand)) rand = min + Math.random() * max | 0
exclude.add(rand)
return rand
}
arr = new Set(arr)
console.log(getRandom(arr))
console.log(getRandom(arr))
console.log(getRandom(arr))
console.log(getRandom(arr))
console.log([...arr])
You could generate an array of the numbers up to the max that you want, then remove the ones that you don't want, and the pick a random element from the resulting array, for example:
const max = 100
const exclude = [2,8,5,6]
const randomIdx = Math.floor(Math.random() * (max + 1 - exclude.length))
const randomNum = [...Array(max + 1).keys()].filter(k => !exclude.includes(k))[randomIdx]
console.log(randomNum)

In JavaScript, is there a way to make 0.84729347293923 into an integer without using any string or regex manipulation?

Given any number between 0 and 1, such as 0.84729347293923, is there a simple way to make it into 84729347293923 without string or regex manipulation? I can think of using a loop, which probably is no worse than using a string because it is O(n) with n being the number of digits. But is there a better way?
function getRandom() {
let r = Math.random();
while (Math.floor(r) !== r) r *= 10;
return r;
}
for (let i = 0; i < 10; i++)
console.log(getRandom());
Integers mod 1 = 0, non integers mod 1 != 0.
while ((r*=10) % 1);
Ok, just want to refactor my code (i realized that was bad so this is what i discovered to correctly get the value as you requested).
NOTE: As the question says that "given any number between 0 and 1", this solution only works for values between 0 and 1:
window.onload = ()=>{
function getLen(num){
let currentNumb = num;
let integratedArray = [];
let realLen = 0;
/*While the number is not an integer, we will multiply the copy of the original
*value by ten, and when the loop detects that the number is already an integer
*the while simply breaks, in this process we are storing each transformations
*of the number in an array called integratedArray*/
while(!(Number.isInteger(currentNumb))){
currentNumb *= 10;
integratedArray.push(currentNumb);
}
/*We iterate over the array and compare each value of the array with an operation
*in which the resultant value should be exactly the same as the actual item of the
*array, in the case that both are equal we assign the var realLen to i, and
*in case that the values were not the same, we simply breaks the loop, if the
*values are not the same, this indicates that we found the "trash numbers", so
*we simply skip them.*/
for(let i = 0; i < integratedArray.length; i++){
if(Math.floor(integratedArray[i]) === Math.floor(num * Math.pow(10, i + 1))){
realLen = i;
}else{
break;
}
}
return realLen;
}
//Get the float value of a number between 0 and 1 as an integer.
function getShiftedNumber(num){
//First we need the length to get the float part of the number as an integer
const len = getLen(num);
/*Once we have the length of the number we simply multiply the number by
*(10) ^ numberLength, this eliminates the comma (,), or point (.), and
*automatically transforms the number to an integer in this case a large integer*/
return num * (Math.pow(10, len));
}
console.log(getShiftedNumber(0.84729347293923));
}
So the explanation is the next:
Because we want to convert this number without using any string, regex or any another thing, first we need to get the length of the number, this is a bit hard to do without using string conversions... so i did the function getLen for this purpose.
In the function getLen, we have 3 variables:
currentNumb: This var is a copy of the original value (the original number), this value help us to found the length of the number and we can do some transforms to this value whitout changing the original reference of the number.
We need to multiply this value any times is needed to transform the number to an integer and then multiplyng this value by ten to ten.
with the help of a while (this method makes the number a false integer).
NOTE: I saw "False integer" because when i was making the tests i realized that in the number is being adding more digits than normal... (Very very strange), so this stupid but important thing makes neccesary the filter of these "trash numbers", so later we proccess them.
integratedArray: This array stores the values of the result of the first while operations, so the last number stored in this array is an integer, but this number is one of the "fake integers", so with this array we need to iterate later to compare what of those stored values are different to the original value multiplied by (10 * i + 1), so here is the hint:
In this case the first 12 values of this array are exactly the same with the operation of Math.floor(num * Math.pow(10, i + 1))), but in the 13th value of the array these values are not the same so... yes!, there are those "trash numbers" that we were searching for.
realLen: This is the variable where we will store the real length of the number converting the float part of this number in an integer.
Some binary search approach:
Its useless if avarage length < 8;
It contains floating point issues.
But hey it is O(log n) with tons of wasted side computations - i guess if one counts them its event worse than just plain multiplication.
I prefer #chiliNUT answer. One line stamp.
function floatToIntBinarySearch(number){
const max_safe_int_length = 16;
const powers = [
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000
]
let currentLength = 16
let step = 16
let _number = number * powers[currentLength]
while(_number % 1 != 0 || (_number % 10 | 0) == 0){
step /= 2
if( (_number % 10 | 0) == 0 && !(_number % 1 != 0)){
currentLength = currentLength - step;
} else {
currentLength = step + currentLength;
}
if(currentLength < 1 || currentLength > max_safe_int_length * 2) throw Error("length is weird: " + currentLength)
_number = number * powers[currentLength]
console.log(currentLength, _number)
if(Number.isNaN(_number)) throw Error("isNaN: " + ((number + "").length - 2) + " maybe greater than 16?")
}
return number * powers[currentLength]
}
let randomPower = 10 ** (Math.random() * 10 | 0)
let test = (Math.random() * randomPower | 0) / randomPower
console.log(test)
console.log(floatToIntBinarySearch(test))

Decompose a number in prime numbers

How can I find a number within the interval (from 1 to given number) which is when decomposed into prime numbers has the maximum amount of them.
Example:
Input: 9
Output: 8
Explanation:
8 = 2 * 2 * 2 (3 primes)
7 = 7 * 1 (1 prime)
6 = 3 * 2 ( 2 primes)
And so on... At the end, we'll see that 8 has the greatest amount of primes in decomposition.
Specification:
If there're several numbers having the same amount of primes in decomposition, return the greatest of them.
Okay, I think I understood your requirement.
Here's a simple script to do what you have asked.
//source of this function: https://jsfiddle.net/JamesOR/RC7SY/
function getAllFactorsFor(remainder) {
var factors = [], i;
for (i = 2; i <= remainder; i++) {
while ((remainder % i) === 0) {
factors.push(i);
remainder /= i;
}
}
return factors;
}
function calculate(x) {
lastFactorCount = 0;
highestNumber = 0;
while (x) {
currentCount = getAllFactorsFor(x).length;
if (currentCount > lastFactorCount) {
lastFactorCount = currentCount;
highestNumber = x;
}
x--;
}
return highestNumber;
}
console.log(calculate(7)); //output: 6
console.log(calculate(11)) //output: 8
This pass the two test cases you have given. I borrowed the getAllFactorsFor() function from a jsfiddle I found since we don't need to reinvent anything ;)
calculate() function takes in an input number, then it loops through every number from x to 0, counting how many factors it has, and it keeps track of the last factor count while decrementing x in each iteration.
Finally it outputs the number with highest factor count. Simple.
Hope it helps!!
Notice that after 2 and 3, the next prime is 5, which is bigger than 2*2 (obviously). Therefore, using 2*2 will ALWAYS be better for amount of prime factors, than any higher prime. The number with the highest amount of 2 as prime factors which is still lower or equal is 2 ** Math.floor(Math.log2(num)). The only thing we need to check is whether replacing the last prime factor 2 with a 3 will still be below the number, as that may happen, and would yield a bigger number. Note again, using more than one 3 would be 3*3 = 9 > 8 = 2*2*2, which cannot be a solution again. All of that together yields that the solution should simply be
const f = num => {
let twoEnd = 2 ** Math.floor(Math.log2(num));
let threeEnd = twoEnd / 2 * 3;
return threeEnd <= num ? threeEnd : twoEnd;
}
Some handling for numbers smaller than 2 may be necessary, depending on the circumstances.

Is this implementation of an in-place shuffle "uniform?" [duplicate]

This question already has answers here:
What distribution do you get from this broken random shuffle?
(10 answers)
Closed 5 years ago.
Sorry if this question is oddly specific; I wasn't sure where else to ask it, though!
I'm working through some problems, and I've found the Fisher-Yates Shuffle, but I want to know if this first shuffle I thought of is uniform or not? I'm not the greatest with probability.. or math... Ha.
The idea is pretty simple; for as many elements as there are in the array, pick two at random and swap them with each other.
function inPlaceShuffle(arr) {
const floor = 0,
ceil = arr.length - 1;
let i = arr.length;
while (i > 0) {
swap(arr, getRandom(floor, ceil), getRandom(floor, ceil));
i--;
}
return arr;
}
function swap(arr, firstIndex, secondIndex) {
const temp = arr[firstIndex];
arr[firstIndex] = arr[secondIndex];
arr[secondIndex] = temp;
}
function getRandom(floor, ceil) {
floor = Math.ceil(floor);
ceil = Math.floor(ceil);
return Math.floor(Math.random() * (ceil - floor + 1)) + floor;
}
Note that every iteration of loop gives n^2 combinations of indexes for change, and n iterations give n^(2n) variants, but this value does not divide n! permutations evenly for n>2, so some permutations will have higher probability than others.
Clear example:
There are 729 results for 6 permutations of {1,2,3}, 729 / 6 = 121. 5, so probability of permutations varies.

Random number between negative and positive value [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Generating random numbers in Javascript in a specific range?
How can i get a random value between, for example, from -99 to 99, excluding 0?
var num = Math.floor(Math.random()*99) + 1; // this will get a number between 1 and 99;
num *= Math.round(Math.random()) ? 1 : -1; // this will add minus sign in 50% of cases
Altogether
var ranNum = Math.ceil(Math.random() * 99) * (Math.round(Math.random()) ? 1 : -1)
This returns what you want
function getNonZeroRandomNumber(){
var random = Math.floor(Math.random()*199) - 99;
if(random==0) return getNonZeroRandomNumber();
return random;
}
Here's a functional fiddle
EDIT
To contribute for future readers with a little debate happened in the comments which the user #MarkDickinson made a indeed relevant contribution to my first code posted, I've decided to make another fiddle with a fast comparison between using Math.floor() and Math.round() functions to return the value the op wanted.
First Scenario: Using var random = Math.round(Math.random()*198) - 99; (My first suggestion)
function getNonZeroRandomNumberWithMathRound(){
var random = Math.round(Math.random()*198) - 99;
if(random==0) return getNonZeroRandomNumber();
return random;
}
Second scenario: Using var random=Math.floor(Math.random()*199) - 99; (Mark suggestion)
function getNonZeroRandomNumberWithMathFloor(){
var random = Math.floor(Math.random()*199) - 99;
if(random==0) return getNonZeroRandomNumber();
return random;
}
Methodology
Since it's a short debate I've chosen fiddle.net to do the comparison.
The test consists of running the above functions 100.000 times and then retrieving how much times the extreme numbers 99 and -99 would appear against a other number, let's say 33 and -33.
The test will then give a simple output consisting of the percentage of appearances from 99 and -99 and the percentage of appearances of 33 and -33.
It'll be used the Webkit implementation from Safari 6.0.2 to the give the output from this answer but anyone can test with your favourite browser late on fiddle.net
Result from first scenario:
Percentage of normal ocurrences:0.97%
Percentage of extreme ocurrences:0.52%
Percentage of extreme ocurrences relative to normal ocurrences:53.4% // Half the chances indeed
Result from second scenario:
Percentage of normal ocurrences:1.052%
Percentage of extreme ocurrences:0.974%
Percentage of extreme ocurrences relative to normal ocurrences:92% //Closer of a fair result with a minimal standard deviation
The result can be seen here: http://jsfiddle.net/brunovieira/LrXqh/
Here's a generalized solution that will let you set the boundaries, and opt in/out of including the 0.
var pos = 99,
neg = 99,
includeZero = false,
result;
do result = Math.ceil(Math.random() * (pos + neg)) - neg;
while (includeZero === false && result === 0);
The pos and neg values are inclusive.
This way there's no requirement that the positive and negative ranges be balanced.
Or if you're worried about the rerun due to a single excluded value, you can just make the initial range less by one, and add 1 to any result greater than or equal to 0.
var pos = 5,
neg = 5,
result;
result = Math.floor(Math.random() * (pos + neg)) - neg;
result = result < 0 ? result : result + 1;
That last line could be shorter if you prefer:
result += (result >= 0)

Categories

Resources