I am using the following code to generate a random number:
function getRandomInt (min, max) {
return Math.floor((Math.random() * (max - min + 1)) + min;
}
What I want to do is add a weighting that favours the numbers at the lower end of the range.
I thought about maybe trying to multiply the numbers by 1/cosine.
Would this work and does anyone know how I might go about it?
Many thanks!
First Solution
You need a function which contains the points (0, 0) and (1, 1). For instance: x^n when n > 0
Math.pow(1, n) === 1
And
Math.pow(0, n) === 0
Therefore, you would just change n depending on how you want the weighting to work.
When n = 1 : y === x
When n > 1 : y <= x
When 0 < n < 1 : y >= x
So, if you want lower values to be favored over higher values, simply use n > 1.
var weighted = Math.pow(Math.random(), 2);
Then you can scale the result as usual.
var scaled = Math.floor(weighted * (max - min + 1)) + min;
Other Functions
Likewise, you could use any continuous function which contains the points (0, 0), (1, 1), and has range and domain of [0, 1].
Sine
y = sin(xπ/2)
Cosine
y = 1 - cos(xπ/2)
EDIT: there was a type in the final formula, log(2+log(x)) is incorrect it should have been log(1+log(x))+1, its fixed now.
If you are using logarithmic weighting, using something like
var x = Math.random();
var weighted = x * Math.log(1+x);
would make 0.5 weigh in at around 0.2, but 1 would only weigh in at around 0.69.
Using this
var x = Math.random();
var weighted = x * Math.log(2 + Math.log(x));
would allow 1 to weigh in at 1. So combine them, and this
var x = Math.random();
var weighted = (x <= 0.5) ? x * Math.log(1 + x) : x * Math.log(1 + Math.log(x))+1;
should do the trick
Related
Im trying to generate two random numbers
let them x and y,
and i want x to be always greater than y.
how can i do that?
You mean something like that?
// get random number between min and max
function random(min, max) {
return Math.floor(min + Math.random() * (max - min));
}
const y = random(0, 10);
const x = random(y + 1, 10);
console.log('x', x);
console.log('y', y);
How about just generating 2 random values and swapping the values if x is smaller?
let [x,y] = [Math.random(), Math.random()];
console.log(x, y);
if (x < y)
[x,y] = [y,x];
console.log(x, y);
/** random integer between min (inclusive) and max (inclusive) */
const random = (min, max) =>
Math.floor(Math.random() * (max-min+1)) + min;
const generateTwoNumbers = (min, max) => {
let r1 = random(min, max-1);
let r2 = random(min, max-1);
if (r2 >= r1)
r2 += 1;
return [Math.max(r1, r2), Math.min(r1, r2)];
}
const [x, y] = generateTwoNumbers(1, 10);
console.log(`x: ${x} y: ${y}`);
First, see Generating random whole numbers in JavaScript in a specific range for how random number generation can be done.
The values r1 and r2 are guaranteed to be different random numbers in the full range. Math.max() and Math.min() ensure that the higher of the two is first, the other second.
The function will generate incorrect numbers if the range given is too small, e.g., generateTwoNumbers(1, 1) will only produce x = 2 and y = 1. Handling the case of such input is left at the discretion of the reader.
One liner.
// Create a tuple of two random numbers, then sort them.
const randomNumbers = () => [...Array(2)].map(() => Math.random()).sort((a, b) => (a > b ? -1 : 1));
// test
for (const _ of Array(50).keys()) {
const [x, y] = randomNumbers();
console.log(x > y);
}
I'm making a snake game and have hit a stop when generating the food coordinates.
I want a random number that is divisible by 10. By that I mean that it has to be a number mod(10) == 0. The snake is of width 10 so in order for the coordinates to match, I need numbers like 80, 130, 10, 40, 200
Only even numbers without singulars are allowed. This is my current code:
let width = 100;
let height = 100;
let x = Math.floor(Math.random()*width/2)*2;
let y = Math.floor(Math.random()*height/2)*2;
console.log(x + " : " + y);
Use 10 in your snippet then (instead of 2):
let width = 100;
let height = 100;
let x = Math.floor(Math.random()*width/10)*10+10;
let y = Math.floor(Math.random()*height/10)*10+10;
console.log(x + " : " + y);
added 10 to avoid 0, I guess that's what you mean on singular. If not, please clarify in the question
this way code generates 10 <= x <= width and 10 <= y <= height, where both x and y are integer multiples of 10.
You can generate a random multiple of 10 between 10 and 150 by first generating a random number between 1 and 15 and then multiplying it by 10. You can do this in plain JavaScript as follows:
var min = 1;
var max = 15;
console.log(Math.floor(Math.random() * (max - min + 1) + min) * 10);
Or, you can do it in a cryptographically secure way with rando.js like this:
console.log(rando(1, 15) * 10);
<script src="https://randojs.com/2.0.0.js"></script>
The current project that I am working on involves a multidimensional world, which can have many more than just 3 dimensions, and need to get values for each position of that world. I already have a good Pseudo Random Number Generator (PRNG) that takes a seed and a single value. What I need is to have a function that can use as many inputs as are provided, and return a value based on those positions. The PRNG also should not have to rely on its previous values to determine it's next state, and should work (as close as possible to) the same on any browser or system.
My current PRNG, works very well for 1 input (xxHash):
function random(seed, x) {
/* mix around the bits in x: */
x = x * 3266489917 + 374761393;
x = (x << 17) | (x >> 15);
/* mix around the bits in y and mix those into x: */
x += seed * 3266489917;
/* Give x a good stir: */
x *= 668265263;
x ^= x >> 15;
x *= 2246822519;
x ^= x >> 13;
x *= 3266489917;
x ^= x >> 16;
/* trim the result and scale it to a float in [0,1): */
return (x & 0x00ffffff) * (1 / 0x1000000);
}
I tried adding more parameters and mixing them up, but that didn't go so well (Below):
function rand(seed, ...prams){
let x = prams[0] + seed;
x = x * 3266489917 + 374761393;
x = (x << 17) | (x >> 15);
/* mix around the bits in y and mix those into x: */
for(let i =1; i< prams.length; i++){
prams[i] *= seed;
x *= prams[i] * 3266489917
}
/* Give x a good stir: */
x *= 668265263;
x ^= x >> 15;
x *= 2246822519;
x ^= x >> 13;
x *= 3266489917;
x ^= x >> 16;
/* trim the result and scale it to a float in [0,1): */
let val = ((x & 0x00ffffff) * (1.0 / 0x1000000))
return val;
}
This one didn't return any errors, but if the inputs were in a different order, the value was the same, which means that rand(seed, 5, 1, 1) === rand(seed, 1, 5, 1) === rand(seed, 1, 1, 5) , Which is not great behavior.
I need a function random(seed, ...position) that will generate a pseudo random number between 0 and 1 that is affected by both the order and all the values in the position array.
Lets say I have a scale with 10 values between a know min and max value. How can I get the nearest value on the scale for value between min and max. Example:
min = 0, max = 10, value = 2.75 -> expected: value = 3
min = 5, max = 6, value = 5.12 -> expected: value = 5.1
min = 0, max = 1, value = 0.06 -> expected: value = 0.1
You could use something like this
function nearest(value, min, max, steps) {
var zerone = Math.round((value - min) * steps / (max - min)) / steps; // bring to 0-1 range
zerone = Math.min(Math.max(zerone, 0), 1) // keep in range in case value is off limits
return zerone * (max - min) + min;
}
console.log(nearest(2.75, 0, 10, 10)); // 3
console.log(nearest(5.12, 5, 6, 10)); // 5.1
console.log(nearest(0.06, 0, 1, 10)); // 0.1
Demo at http://jsfiddle.net/gaby/4RN37/1/
Your scenario doesn't make much sense to me. Why does .06 round to 1 and not .1 but 5.12 rounds to 5.1 with the same scale (1 integer)? It's confusing.
Either way, if you want to round to a precise # of decimal places, check this out:
http://www.javascriptkit.com/javatutors/round.shtml
var original=28.453
1) //round "original" to two decimals
var result=Math.round(original*100)/100 //returns 28.45
2) // round "original" to 1 decimal
var result=Math.round(original*10)/10 //returns 28.5
3) //round 8.111111 to 3 decimals
var result=Math.round(8.111111*1000)/1000 //returns 8.111
With this tutorial, you should be able to do exactly what you want.
Perhaps more comprehensible:
var numberOfSteps = 10;
var step = (max - min) / numberOfSteps;
var difference = start - min;
var stepsToDifference = Math.round(difference / step);
var answer = min + step * stepsToDifference;
This also allows you to change the number of steps in your sequence.
I suggest something like that :
var step = (max - min) / 10;
return Math.round(value / step) * step;
I had the problem where I was getting 5.7999997 instead of the weanted 5.8 for example. Here was my first fix (for java...).
public static float nearest(float val, float min, float max, int steps) {
float step = (max - min) / steps;
float diff = val - min;
float steps_to_diff = round(diff / step);
float answer = min + step * steps_to_diff;
answer = ((int) (answer * steps)) / (float) steps;
return answer;
}
However using this on nearest(6.5098, 0, 10, 1000) I would get 6.509 instead of the wanted 6.51.
This solved it for me (watch out for overflows when values are really large):
public static float nearest(float val, float min, float max, int steps) {
val *= steps;
min *= steps;
max *= steps;
float step = (max - min) / steps;
float diff = val - min;
float steps_to_diff = round(diff / step);
float answer = min + step * steps_to_diff;
return answer / (float) steps;
}
var step = 10;
return Math.ceil(x / step) * step;
Ive got a bit stuck figuring it out for the negative direction? it must be really simple, but just cant seem to get it!
x = current x position
dir = direction of motion on x axis
if (tween == 'linear'){
if (dir == 1) {
x += (x / 5);
}
else if (dir == -1){
//what here??
}
}
What's missing here is that you need to consider deviations from the starting point, not x=0 (and also consider the sign of the direction as well, which others are stating correctly). That is, if your starting point is x0, your equation should be more like:
x += (x-x0)/5
Here's the figure for motion in the positive and negative directions (note that position is on the vertical axis and time on the horizontal)
And here's the Python code. (Note that I've added in a dt term, since it's too weird to do dynamic simulation without an explicit time.)
from pylab import *
x0, b, dt = 11.5, 5, .1
xmotion, times = [], []
for direction in (+1, -1):
x, t = x0+direction*dt/b, 0 # give system an initial kick in the direction it should move
for i in range(360):
x += dt*(x-x0)/b
t += dt
xmotion.append(x)
times.append(t)
plot(times, xmotion, '.')
xlabel('time (seconds)')
ylabel('x-position')
show()
x += (abs(x) / 5) * dir;
If you do something like x -= (x/5), it's going to be impossible to cross x = 0 - as x gets close to 0, it starts changing less and less. Try using a minimum increment
v = abs(x) / 5;
x += ((v > MINVEL) ? v : MINVEL) * dir;
if (tween == 'linear') {
x += (x / 5) * dir;
}
In the end I added a frame counter (t) and went with:
x = -(change*dir) * (t /= 10) * (t - 2) + x;
from my fav as3 tweener lib:
http://code.google.com/p/tweener/source/browse/trunk/as3/caurina/transitions/Equations.as