Related
I'm trying to generate random numbers in javascript that are evenly distributed between 2 floats. I've tried using the method from the mozilla docs to get a random number between 2 values but it appears to cluster on the upper end of the distribution. This script:
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
function median(values) {
if (values.length === 0) throw new Error("No inputs");
values.sort(function (a, b) {
return a - b;
});
var half = Math.floor(values.length / 2);
if (values.length % 2)
return values[half];
return (values[half - 1] + values[half]) / 2.0;
}
const total = 10_000_000
let acc = []
for (i = 0; i < total; i++) {
acc.push(getRandomArbitrary(1e-10, 1e-1))
}
console.log(median(acc))
consistently outputs a number close to .05 instead of a number in the middle of the range (5e-5). Is there any way to have the number be distributed evenly?
Thank you!
EDIT: changed script to output median instead of mean.
function log10(x) { return Math.log(x)/Math.LN10; }
function getLogRandomArbitrary(min, max) {
return Math.pow(10, log10(min) + (Math.random() * (log10(max) - log10(min))));
}
function median(values) {
if(values.length === 0) throw new Error("No inputs");
let a = [...values].sort((a,b)=>a-b);
return a[Math.floor(a.length/2)];
}
const iterations = 1_000_000;
let a = [];
for (let i=0; i<iterations; i++) {
a.push(getLogRandomArbitrary(1e-10, 1e-1));
}
console.log(median(a));
console.log(log10(median(a)));
I need some help with a task which is about creating a function that only accepts integer numbers to then multiply each other until getting only one digit. The answer would be the times:
Example: function(39) - answer: 3
Because 3 * 9 = 27, 2 * 7 = 14, 1 * 4 = 4 and 4 has only one digit
Example2: function(999) - answer: 4
Because 9 * 9 * 9 = 729, 7 * 2 * 9 = 126, 1 * 2 * 6 = 12, and finally 1 * 2 = 2
Example3: function(4) - answer: 0
Because it has one digit already
So trying to figure out how to solve this after many failures, I ended up coding this:
function persistence(num) {
let div = parseInt(num.toString().split(""));
let t = 0;
if(Number.isInteger(num) == true){
if(div.length > 1){
for(let i=0; i<div.length; i++){
div = div.reduce((acc,number) => acc * number);
t += 1;
div = parseInt(div.toString().split(""))
if(div.length == 1){
return t } else {continue}
} return t
} else { return t }
} else { return false }
}
console.log(persistence(39),3);
console.log(persistence(4),0);
console.log(persistence(25),2);
console.log(persistence(999),4);
/*
output: 0 3
0 0
0 2
0 4
*/
It seems I could solve it, but the problem is I don't know why those 0s show up. Besides I'd like to receive some feedback and if it's possible to improve those codes or show another way to solve it.
Thanks for taking your time to read this.
///EDIT///
Thank you all for helping and teaching me new things, I could solve this problem with the following code:
function persistence(num){
let t = 0;
let div;
if(Number.isInteger(num) == true){
while(num >= 10){
div = (num + "").split("");
num = div.reduce((acc,val) => acc * val);
t+=1;
} return t
}
}
console.log(persistence(39));
console.log(persistence(4));
console.log(persistence(25));
console.log(persistence(999));
/*output: 3
0
2
4
*/
You've got a few issues here:
let div = parseInt(num.toString().split("")); You're casting an array to a number, assuming you're trying to extract the individual numbers into an array, you were close but no need for the parseInt.
function persistence(input, count = 0) {
var output = input;
while (output >= 10) {
var numbers = (output + '').split('');
output = numbers.reduce((acc, next) {
return Number(next) * acc;
}, 1);
count += 1;
}
return count;
};
For something that needs to continually check, you're better off using a recurssive function to check the conditions again and again, this way you won't need any sub loops.
Few es6 features you can utilise here to achieve the same result! Might be a little too far down the road for you to jump into es6 now but here's an example anyways using recursion!
function recursive(input, count = 0) {
// convert the number into an array for each number
const numbers = `${input}`.split('').map(n => Number(n));
// calculate the total of the values
const total = numbers.reduce((acc, next) => next * acc, 1);
// if there's more than 1 number left, total them up and send them back through
return numbers.length > 1 ? recursive(total, count += 1) : count;
};
console.log(recursive(39),3);
console.log(recursive(4),0);
console.log(recursive(25),2);
console.log(recursive(999),4);
function persistance (num) {
if (typeof num != 'number') throw 'isnt a number'
let persist = 0
while(num >= 10) {
let size = '' + num
size = size.length
// Get all number of num
const array = new Array(size).fill(0).map((x, i) => {
const a = num / Math.pow(10, i)
const b = parseInt(a, 10)
return b % 10
})
console.log('here', array)
// actualiser num
num = array.reduce((acc, current) => acc * current, 1)
persist++
}
return persist
}
console.log(persistance(39))
console.log(persistance(999))
console.log() can take many argument...
So for example, console.log("A", "B") will output "A" "B".
So all those zeros are the output of your persistence function... And the other number is just the number you provided as second argument.
So I guess you still have to "persist"... Because your function always returns 0.
A hint: You are making this comparison: div.length > 1...
But div is NOT an array... It is a number, stringified, splitted... And finally parsed as integer.
;) Good luck.
Side note, the calculation you are attempting is known as the Kaprekar's routine. So while learning JS with it... That history panel of the recreational mathematic wil not hurt you... And may be a good line in a job interview. ;)
My best hint
Use the console log within the function to help you degug it. Here is your unchanged code with just a couple of those.
function persistence(num) {
let div = parseInt(num.toString().split(""));
let t = 0;
console.log("div.length", div.length)
if (Number.isInteger(num) == true) {
if (div.length > 1) {
for (let i = 0; i < div.length; i++) {
div = div.reduce((acc, number) => acc * number);
t += 1;
div = parseInt(div.toString().split(""));
if (div.length == 1) {
console.log("return #1")
return t;
} else {
continue;
}
}
console.log("return #2")
return t;
} else {
console.log("return #3")
return t;
}
} else {
console.log("return #4")
return false;
}
}
console.log(persistence(39), 3);
console.log(persistence(4), 0);
console.log(persistence(25), 2);
console.log(persistence(999), 4);
I'm generating random numbers from 1 to 20 by calling generateRandom(). How can I exclude some values, say 8 and 15?
function generateRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var test = generateRandom(1, 20)
it should be or instead of and
function generateRandom(min, max) {
var num = Math.floor(Math.random() * (max - min + 1)) + min;
return (num === 8 || num === 15) ? generateRandom(min, max) : num;
}
var test = generateRandom(1, 20)
One way, which will maintain the generator's statistical properties, is to generate a number in [1, 18]. Then apply, in this order:
If the number is 8 or more, add 1.
If the number is 15 or more, add 1.
I'd be reluctant to reject and re-sample as that can cause correlation plains to appear in linear congruential generators.
Right now I'm using this and it works without causing browser issues with infinities loops, also tested in mobile devices (using Ionic/Cordova):
function getRandomIndex(usedIndexs, maxIndex) {
var result = 0;
var min = 0;
var max = maxIndex - 1;
var index = Math.floor(Math.random()*(max-min+1)+min);
while(usedIndexs.indexOf(index) > -1) {
if (index < max) {
index++;
} else {
index = 0;
}
}
return index;
}
To generate random number between 1 and 20 excluding some given numbers, you can simply do this:
function generateRandom(min, max, exclude) {
let random;
while (!random) {
const x = Math.floor(Math.random() * (max - min + 1)) + min;
if (exclude.indexOf(x) === -1) random = x;
}
return random;
}
const test = generateRandom(1, 20, [8, 15]);
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* Pass all values as an array, as 3rd argument which values shouldn't be generated by the function.
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
const minimum = Math.ceil(min);
const maximum = Math.floor(max);
return Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
}
function getRandomIntExcludingExistingNumbers(min, max, excludeArrayNumbers) {
let randomNumber;
if(!Array.isArray(excludeArrayNumbers)) {
randomNumber = getRandomInt(min, max);
return randomNumber;
}
do {
randomNumber = getRandomInt(min, max);
} while ((excludeArrayNumbers || []).includes(randomNumber));
return randomNumber;
}
const randomNumber = getRandomIntExcludingExistingNumbers(1, 10, [1, 2, 4, 5, 9]);
// It will return random integer between 1 to 10 excluding 1,2,4,5,9
Explanation:
getRandomInt function generates random numbers between min and max values.
I am utilizing that function to make "getRandomIntExcludingExistingNumbers" function to avoid specific values.
we will simply call getRandomInt(min, max) values.
Then in do while loop we will check if randomly generated values belongs to any of the values which shouldn't be generated.
If it is unique integer outside exclude values then we will return the value.
If our value is from the excluded values, then from do -- while loop, we will once again call getRandomInt to generate new values.
Here is a slightly modified answer that is similar to all the others but it allows your to pass a single or an array of failing numbers
function generateRandom(min, max, failOn) {
failOn = Array.isArray(failOn) ? failOn : [failOn]
var num = Math.floor(Math.random() * (max - min + 1)) + min;
return failOn.includes(num) ? generateRandom(min, max, failOn) : num;
}
You could make use of a recursive function
function generateRandom(min, max, num1, num2) {
var rtn = Math.floor(Math.random() * (max - min + 1)) + min;
return rtn == num1 || rtn == num2 ? generateRandom(min, max, num1, num2) : rtn;
}
I think it should be like this, if you want good distribution on all numbers.
and, for this solution, it is required to higher max than 15 and lower min that 8
function generateRandom(min, max) {
var v = Math.floor(Math.random() * (max - min + 1 - 2)) + min;
if (v == 8) return max-1;
else if (v == 15) return max-2;
else return v;
}
var test = generateRandom(1, 20)
You can build an array dynamically. Depending on where you are getting the excluded numbers. Something like:
var excluded = [8, 15];
var random = [];
for(var i = min; i <= max; i++) {
if(excluded.indexOf(i) !== -1) {
random.push(i);
}
}
Then use the tips found in the answer for this post: How can I generate a random number within a range but exclude some?. Should get you to where you want to go.
Here is a really stupidly overcomplicated solution...
<script>
var excludedNumbers = [];
excludedNumbers.push(8);
excludedNumbers.push(15);
excludedNumbers.push(10);
var array = generateExclude(excludedNumbers, 1, 20);
function generateExclude(excludedNumbers, min, max){
var newNumbers = [];
for(var i = min; i <= max; i++) {
for(var j = 0; j < excludedNumbers.length; j++) {
var checker = $.inArray(i, excludedNumbers)
if(checker > -1){
}else{
if($.inArray(i, newNumbers)<= -1){
newNumbers.push(i);
}
}
};
};
return newNumbers;
}
function generateRandomNumbers(items){
var num = items[Math.floor(Math.random()*items.length)];;
return num;
}
console.log(generateRandomNumbers(array))
</script>
I have answered a similar question for Java: Generate random numbers except certain values. I just copy and paste the answer as follows.
Actually, we do not need to use contains(random) with a while loop.
To simplify the question, let's see what happens if we only have one excluding value. We can split the result to 2 parts. Then the number of possible values is range-1. If the random number is less than the excluded value, just return it. Otherwise, we could add 1.
For multiple excluding values, We can split the result set into size+1 parts, where size means the number of excluding values. Then the number of possible values is range-size. Then we sort excluding values in ascending order. If random number is less than the excluding value minus i, then we just return the random number add i, where i is the index of the the excluding value.
public int generateRandomNumberWithExcepts(int start, int end, List<Integer> excepts) {
int size = excepts.size();
int range = end - start + 1 - size;
int randNum = random.nextInt(range) + start;
excepts.sort(null); // sort excluding values in ascending order
int i=0;
for(int except : excepts) {
if(randNum < except-i){
return randNum + i;
}
i++;
}
return randNum + i;
}
I've read through all these answers and they differ a lot in philosophy, so I thought I might add my very own 2 bits, despite of this question having an answer, because I do think there is a better and more elegant way of approaching this problem.
We can make a function that takes min, max and blacklist as parameters and outputs a random result without using recursion (and with close to 0 if statements):
const blrand = function(min, max, blacklist) {
if(!blacklist)
blacklist = []
let rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
let retv = 0;
while(blacklist.indexOf(retv = rand(min,max)) > -1) { }
return retv;
}
usage:
let randomNumber = blrand(0, 20, [8, 15]);
You can simply do like this
function generatedRandExclude(showed,max) {
let randNo = -1;
while(showed.length < max) {
randNo = Math.floor(Math.random() * Math.floor(max));
if(!showed.includes(randNo)) {
showed.push(randNo);
break;
}
}
return randNo;
}
let showed = [];
function run() {
console.log(generatedRandExclude(showed,6));
}
run();
run();
run();
run();
generatedRandExclude generate random number excluded using array showed.
This is a simple and neat idea, I am a electromechanical engineer and I am just learning JS.
This is going to print a random numeber between 1 and 100.
Except 8 and 15
var r; // this is the random integer.
var val; //this will serve as validator for the random integer.
val=0;
while(val==0) {
r=Math.round(Math.random()*100)+1;
if(r!=8 && r!=15){val=1;} //a valid number will be any number different from 8 and 15
//then validator will change and go out from the loop.
}
document.write(r);
You could take an offset for random values greater or equal than zerow ith a sorted (ascending) array and return a sum with adjusted random value.
const
getRandomWithoutZero = (lower, upper, gaps) => () => {
const r = Math.floor(Math.random() * (upper - lower + 1 - gaps.length) + lower);
return gaps.reduce((s, g) => s + (s >= g), r);
},
random = getRandomWithoutZero(-9, 9, [-3, 0, 4]),
count = {};
for (let i = 0; i < 1.6e6; i++) {
const r = random();
count[r] = (count[r] || 0) + 1;
}
console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I need to generate two different random numbers, they can't be equal to each other or to a third number. I tried to use a lot of if's to cover every possibility but, it seems my algorithm skills are not that good.
Can anyone help me on this?
var numberOne = Math.floor(Math.random() * 4);
var numberTwo = Math.floor(Math.random() * 4);
var numberThree = 3; // This number will not always be 3
if((numberOne == numberThree) && (numberOne + 1 < 3)) {
numberOne++;
} else if ((numberOne == numberThree) && (numberOne + 1 == 3)) {
numberOne = 0;
}
if ((numberOne == numberTwo) && (numberOne+1 < 3)) {
if (numberOne+1 < 3) {
numberOne++;
} else if(numberThree != 0) {
numberOne = 0;
}
}
This is what I have so far, the next step would be:
if (numberTwo == numberThree) {
(...)
}
Is my line of thought right?
Note: Numbers generated need to be between 0 and 3. Thanks in advance.
You can run a while loop until all numbers are different.
// All numbers are equal
var numberOne = 3;
var numberTwo = 3;
var numberThree = 3;
// run this loop until numberOne is different than numberThree
do {
numberOne = Math.floor(Math.random() * 4);
} while(numberOne === numberThree);
// run this loop until numberTwo is different than numberThree and numberOne
do {
numberTwo = Math.floor(Math.random() * 4);
} while(numberTwo === numberThree || numberTwo === numberOne);
Here is the jsfiddle with the above code based on #jfriend00's suggestion http://jsfiddle.net/x4g4kkwc/1.
Here is the original working demo: http://jsfiddle.net/x4g4kkwc/
You can create an array of random possibilities and then remove items from that array as they are used, selecting future random numbers from the remaining values in the array. This avoids looping trying to find a value that doesn't match previous items.
function makeRandoms(notThis) {
var randoms = [0,1,2,3];
// faster way to remove an array item when you don't care about array order
function removeArrayItem(i) {
var val = randoms.pop();
if (i < randoms.length) {
randoms[i] = val;
}
}
function makeRandom() {
var rand = randoms[Math.floor(Math.random() * randoms.length)];
removeArrayItem(rand);
return rand;
}
// remove the notThis item from the array
if (notThis < randoms.length) {
removeArrayItem(notThis);
}
return {r1: makeRandom(), r2: makeRandom()};
}
Working demo: http://jsfiddle.net/jfriend00/vhy6jxja/
FYI, this technique is generally more efficient than looping until you get something new when you are asking to randomly select most of the numbers within a range because this just eliminates previously used numbers from the random set so it doesn't have to keep guessing over and over until it gets an unused value.
This version minimizes the number of calls to random like you did, but is a bit simpler and not biased. In your version, there is a 2/4 chance that numberOne goes to 0, and a 1/4 chance if goes to 1 and 2. In my version there are equal odds of numberOne ending up as 0, 1 or 2).
i0 = Math.floor(Math.random() * 4); //one of the 4 numbers in [0, 4), namely 3
i1 = Math.floor(Math.random() * 3); //only 3 possibilities left now
i2 = Math.floor(Math.random() * 2); //only two possibilities left now
x0 = i0;
x1 = i1 + (i1 >= i0 ? 1 : 0);
x2 = i2 + (i2 >= i0 ? 1 : 0) + (i2 >= i1 ? 1 : 0);
Its a special case of the array-shuffling version deceze mentioned but for when you have only two numbers
I'm not sure of what you're trying to do (or actually, why is your code so complicated for what I understood). It might not be the most optimized code ever, but here is my try :
var n3 = 3;
var n2 = Math.floor(Math.random() * 4);
var n1 = Math.floor(Math.random() * 4);
while(n1 == n3)
{
n1 = Math.floor(Math.random() * 4);
}
while (n2 == n1 || n2 == n3)
{
n2 = Math.floor(Math.random() * 4);
}
EDIT : Damn, too late ^^
var n = 4; //to get two random numbers between 0 and 3
var n3 = 2; //for example
var n1 = Math.floor(Math.random(n-1));
var n2 = Math.floor(Math.random(n-2));
if(n1 >= n3) {
n1++;
if(n2 >= n3)
n2++;
if(n2 >= n1)
n2++;
} else {
if(n2 >= n1)
n2++;
if(n2 >= n3)
n2++;
}
You need to compare n2 with the minimum of n1 and n3 first to ensure you do not have an equality:
Suppose n1=1 and n3=2. If you get n2=1 and compare it first with n3, you won't increase n2 in the first step. In the second step, you would increase it since n2 >= n1. In the end, n2 = 2 = n3.
This algorithm guarantees to have a uniform distribution, and you only call twice Math.random().
var rangeTo = 4;
var uniqueID = (function () {
var id, cache = [];
return function () {
id = Math.floor((Math.random() * (new Date).getTime()) % rangeTo);
var cacheLength = cache.length;
if (cacheLength === rangeTo) {
throw new Error("max random error");
};
var i = 0
while (i < cacheLength) {
if (cache[i] === id) {
i = 0;
id = Math.floor((Math.random() * (new Date).getTime()) % rangeTo);
}
else {
i++;
}
}
cache.push(id);
return id;
};
})();
ES 6 Version:
This is basically a function like already mentioned above, but using the an Arrow function and the Spread operator
const uniqueRandom = (...compareNumbers) => {
let uniqueNumber;
do {
uniqueNumber = Math.floor(Math.random() * 4);
} while(compareNumbers.includes(uniqueNumber));
return uniqueNumber;
};
const numberOne = uniqueRandom();
const numberTwo = uniqueRandom(numberOne);
const numberThree = uniqueRandom(numberOne, numberTwo);
console.log(numberOne, numberTwo, numberThree);
Be aware that back-to-back calls to Math.random() triggers a bug in chrome as indicated here, so modify any of the other answers by calling safeRand() below.:
function safeRand() {
Math.random();
return Math.random();
}
This still isn't ideal, but reduces the correlations significantly, as every additional, discarded call to Math.random() will.
Generally, in pseudo-code, I do :
var nbr1 = random()
var nbr2 = random()
while (nbr1 == nbr2) {
nbr2 = random();
}
This way you'll get two different random numbers.
With an additional condition you can make them different to another (3rd) number.
I've got this number as a integer 439980
and I'd like to place a decimal place in 2 places from the right. to make it 4399.80
the number of characters can change any time, so i always need it to be 2 decimal places from the right.
how would I go about this?
thanks
function insertDecimal(num) {
return (num / 100).toFixed(2);
}
Just adding that toFixed() will return a string value, so if you need an integer it will require 1 more filter. You can actually just wrap the return value from nnnnnn's function with Number() to get an integer back:
function insertDecimal(num) {
return Number((num / 100).toFixed(2));
}
insertDecimal(99552) //995.52
insertDecimal("501") //5.01
The only issue here is that JS will remove trailing '0's, so 439980 will return 4399.8, rather than 4399.80 as you might hope:
insertDecimal(500); //5
If you're just printing the results then nnnnnn's original version works perfectly!
notes
JavaScript's Number function can result in some very unexpected return values for certain inputs. You can forgo the call to Number and coerce the string value to an integer by using unary operators
return +(num / 100).toFixed(2);
or multiplying by 1 e.g.
return (num / 100).toFixed(2) * 1;
TIL: JavaScript's core math system is kind of weird
Another Method
function makeDecimal(num){
var leftDecimal = num.toString().replace('.', ''),
rightDecimal = '00';
if(leftDecimal.length > 2){
rightDecimal = leftDecimal.slice(-2);
leftDecimal = leftDecimal.slice(0, -2);
}
var n = Number(leftDecimal+'.'+rightDecimal).toFixed(2);
return (n === "NaN") ? num:n
}
makeDecimal(3) // 3.00
makeDecimal(32) // 32.00
makeDecimal(334) // 3.34
makeDecimal(13e+1) // 1.30
Or
function addDecimal(num){
var n = num.toString();
var n = n.split('.');
if(n[1] == undefined){
n[1] = '00';
}
if(n[1].length == 1){
n[1] = n[1]+'0';
}
return n[0]+'.'+n[1];
}
addDecimal(1); // 1.00
addDecimal(11); // 11.00
addDecimal(111); // 111.00
Convert Numbers to money.
function makeMoney(n){
var num = n.toString().replace(/\$|\,/g,'');
if(isNaN(num))
num = "0";
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = "0" + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+','+num.substring(num.length-(4*i+3));
return (((sign)?'':'-') + '$' + num + '.' + cents);
}
One More.
function addDecimal(n){
return parseFloat(Math.round(n * 100) / 100).toFixed(2);
}