JavaScript biased results? - javascript

Let's say I have two items in an array, e.g:
["a", "b"]
Now let's say I have a function called random that chooses a random item from this array, e.g:
function random() {
// do awesome random stuff here...
return random_choice;
}
How can I get the random function to return "a" 80% of the time and "b" 20% of the time?
I'm not really sure as to what this is called but for example if I ran the console.log(random()); 10 times the result should look a little something like this:
>>> "a"
>>> "a"
>>> "a"
>>> "a"
>>> "a"
>>> "a"
>>> "a"
>>> "a"
>>> "b"
>>> "b"
"a" get's returned 8/10 times and "b" gets returned 2/10 times.
NOTE: the "results" above are just an example, I understand that they won't always be that perfect and they don't have to be.

Quickest answer would be:
var result = Math.random() >= 0.2 ? "a" : "b";

Generalized solution for any number of values
function biasedRandomSelection(values, probabilities) {
// generate random number (zero to one).
var rand = Math.random();
// cumulative probability, starting at 0
var cumulativeProb = 0;
// loop through the raw `probabilities` array
for(var i=0; i<probabilities.length; i++) {
// increment cumulative probability
cumulativeProb += probabilities[i];
// test for `rand` being less than the cumulative probaility;
// when true, return return the corresponding value.
if(rand < cumulativeProb) return values[i];
}
}
The knack here is to test against a rolling "cumulative probability", derived from the raw probabilities.
Sample calls :
biasedRandomSelection(['a', 'b'], [0.8, 0.2]); // as per the question
biasedRandomSelection(['a', 'b'], [0.2, 0.8]); // reversed probailities
biasedRandomSelection(['a', 'b', 'c', 'd', 'e'], [0.4, 0.1, 0.2, 0.2, 0.1]); // larger range of values/probailities
Demo
As written, biasedRandomSelection() performs no range checking.
A safer version would check that :
values and probabilities were congruant
the sum of the probabilities was 1.

Math.random() returns a number in [0;1). Just use p < 0.2 / p < 0.8 to have a biased result instead of the the unbiased p < 0.5.
If you want the first N outcomes to be deterministic, then you can use a simple counter i++ < N.

A bit extended:
var array="a".repeat(8)+"b".repeat(2);
var random=()=>array[Math.floor(Math.random()*array.length)];
alert(random());
This also works for more than two results and all different kinds of probability.
Note that array is not really an array but rather a lookupstring
..
http://jsbin.com/besapetidi/edit?console

Related

Javascript math.floor and math.random question

var letters = ["A", "B", "C", "D"];
var rnd = Math.random();
var rndK = letters[Math.floor(rnd*letters.length)];
return rndK;
My question to this is, I've run it a couple of times and it prints D sometimes, but I don't really understand why, since to my knowledge,
math.random() returns a pseudorandom number between 0 and 1 but not 1,
math.floor() returns the highest integer that's less or equal to the value, rounding down essentially.
shouldn't D only be printed out when the rnd gives a 1, but since math.floor() rounds down, this shouldn't be possible?
I'm probably missing something really obvious here, thanks if anyone can explain it for a complete beginner to javascript.
You're right, math.random() only returns a value between 0 and 1. Multiplying it by letters.length, which is 4, and flooring it will only return a value between 0 and 3, never 4. That will still return D sometimes, because the index of D is 3. Remember, the index of the element is the element's place minus 1. So the index of A is 0, the index of B is 1, the index of C is 2, and the index of D is 3. If you don't want D returned, multiply math.random() by letters.length - 1.
Math.floor(rnd*letters.length)
Returns a number between 0 and 3 in your case. Because letters.length === 4
letters[0] === "A"
letters[3] === "D"
So everything works as expected :)

JavaScript Roman Numeral Converter

I am not able to understand this solution properly. I understood the Array declaration part but I am not sure what's going on in the while loop.
function roman(num) {
var decimalValue = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
var romanNumeral = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I'];
var romanized = '';
for (var index = 0; index < decimalValue.length; index++) {
while (decimalValue[index] <= num) {
romanized += romanNumeral[index];
num -= decimalValue[index];
}
}
return romanized;
}
Next time you're stuck on a loop-based problem like this, I would suggest learning about the debugger; command and breakpoints.
Let's use a specific number as an example, say... 2,652. Here's what will happen:
Starting with 1,000 (the first number in decimalValue), check if 2,562 > 1,000.
It is! So, we know that the Roman numeral for 2,652 has at least one M in it. We add M to our output Roman numeral.
We've "accounted for" 1,000 of our number as a numeral, so we remove 1,000 from the number. We now have 1,562.
We jump back up to checking if num > 1,000. It still is. So, we add another M and subtract another 1,000. Now we have 562 of our number "unaccounted for."
This time, when we jump up to the start of our while() loop to test if num > 1,000, we find that it isn't the case! So the loop does not run this time.
This process repeats for all the numbers in decimalValue; all the numbers that have Roman numeral equivalents.
So, we check 900/CM, and find that this number (which is now down to 562) can not be represented as a sum including 900.
Next, we check 500, and find that it can! We add the Roman numeral for 500 to our current romanized string and carry on. We now have MMD and our number is down to 62 "unaccounted for" digits/units/whatever we're counting.
The next number to catch our while() loop is 50, since 62 > 50. We add the L for 50 and bring our number down to 12. Then again on 10, and we add an X. Finally, we match on the last item in decimalValue, 1, twice, and add two Is.
Our final string for this number, 2,652, is MMDXII.
The While loop does a comparison starting from index zero to the last and compares if the value of num passed in is less that the value at index of decimal value array if it is, It will then it appends(concatenate) the ruman numeral at that particular index to the randomize and subtract the equivalent number in decimal(mutate the num variable) from the num which was sent in.
It then checks if num is still greater than the value at that particular index indicating decimal.
taking a walk through with 3002 as example.
First check if index 0 which has 1000 is less than 3002 true
Set randomize to ruman numeral at position index. In this case we have 'M' then subtract decimal at position index from num(3002) we now have num = 2002.
The while loop iterate again and check is 1000 less than 2002? yes it is so it will execute the body of the while loop again.
Append(Concatenate the value at position index(which has not changed yet) to the randomize variable this case index is still zero so we appending 'M' now randomize is 'MM'. Subtract the decimal at position index(0) from num(2002) we now have num = 1002.
Iterate the while loop and check if decimal value at position index(0) of the decimalValue array is less than num(1002) which is true in this case. execute the loop as before.
Append(Concatenate the value at position index(which has not changed yet) to the randomize variable this case index is still zero so we appending 'M' now randomize is 'MMM'. Subtract the decimal at position index(0) from num(1002) we now have num = 2.
Iterate the while loop and check if decimal value at position index(0) of the decimalValue array is less than num(2) which is false in this case. Stop execution of the loop and increment the value of index in the for loop and do the checks again. till you reach the end.
decimalValue[i] represents the same value as romanNumeral[i] for any i. This represents the same data as if the author used a object {4:"IV", 5:"V", ...} except objects to not preserve order. Since the author wants to check larger numbers before smaller numbers, they use this to preserve order and also associate the decimal values with the Roman Numerals.
The loop is confusing because javascript uses + to represent both numerical addition, 2+4==6, and string concatenation, "a"+"b"=="ab".
romanized += romanNumeral[index] means append the string contained in romanNumberal[index] to the end of the string romanized.
num -= decimalValue[index]; means decrease num by the number contained in decimalValue[index]
//start at the big values that have roman number codes, then try smaller values
for (var index = 0; index < decimalValue.length; index++) {
//if the value we are testing is less or equal to num
// (actually loop but for reasons explained below)
while (decimalValue[index] <= num) {
//append the string in romanNumberal to
//the end of the string in the variable romanized
romanized += romanNumeral[index];
//from the number num, substract the
//value we just added to romanized
num -= decimalValue[index];
//what about a case like 3, which needs
//repeated letters in that case "III".
//That is why this is a while statement and not an if.
//the while loop keeps processing
//those cases until we have enough repeated letters.
}
}
When we need more than one of the same the same letter, then decimalvalue[index] will still be less than or equal to num.
This is because when we reach decimalvalue[index], we know that num < decimalvalue[index-1] (except for the start), because the while loop prevents index from increasing until that is true.
Often the loop only runs once. For example, going from decimalvalue[index] == 10 to decimalvalue[index] == 9 loop only runs once at most because num < 10 and 10-9==1 which is less than 9. So then, the while loop acts as just an if statement.
The loop only loops for values where duplicate letters are valid in roman numerals, because that is were the drop in value between decimalvalue[i-1] and decimal[i] is great enough. More precisely those are the only times when decimalvalue[i-1]/decimalvalue[i] >= 2 (that is 2 or more of a value in decimalvalue[i] fits in the previous decimalvalue)
if you know the division algorithm from math this is kinda like that.
Found this codepen on google. The code is pretty straightforward, I hope it will help.
Roman Numeral Converter in Javascript
function convert(num){
num = parseInt(num);
var result = '',
ref = ['M','CM','D','CD','C','XC','L','XL','X','IX','V','IV','I'],
xis = [1000,900,500,400,100,90,50,40,10,9,5,4,1];
if (num >= 4000) {
num += ''; // need to convert to string for .substring()
result = '<span style="border-top: 1px solid; margin-top: 2px; display: inline-block; padding-top: 0px;">'+convert(num.substring(0,num.length-3))+'</span>';
num = num.substring(num.length-3);
}
for (x = 0; x < ref.length; x++){
while(num >= xis[x]){
result += ref[x];
num -= xis[x];
}
}
return result;
}
$('input').on('keyup keydown change',function(e){
var $this = $(this),
val = $this.val();
if (val.length == 0) return $('#result').html('');
if (isNaN(val)) return $('#result').html('Invalid input');
if (e.type == 'keydown'){
if (e.keyCode === 38) $this.val(++val);
if (e.keyCode === 40) $this.val(--val);
}
if (val < 1) return $('#result').html('Number is too small');
$('#result').html(convert(val));
})

Is it possible to pack two integers to a hexadecimal and get them back

I have a weird requirement,
My destination only supports one integer, But I want to send two integers to it and later I want to get them back from a response.
for example,
allowed input:
{
'task': 2
}
I have subtask kind of a logic in my side, But my target is not aware of this. So, without letting know the target, can I somehow pack two integers and get decode them back in future?
Can this be achieved with hexadecimal?
You can combine any two numbers and get both numbers back using their product (a * b) as long as a * (a * b) + b < Number.MAX_SAFE_INTEGER
Here's a demo snippet:
(() => {
document.addEventListener("click", handleStuff);
// formula: c = (a * (a * b)) + b
// as long as c < 9007199254740991
const combine = (a, b) => ({
a: a,
b: b,
get c() { return this.a * this.b; },
get combined() { return this.a * this.c + this.b; },
get unraveled() { return [
Math.floor(this.combined / this.c),
this.combined % this.c ]; }
});
const log = txt => document.querySelector("pre").textContent = txt;
let numbers = combine(
+document.querySelector("#num1").value,
+document.querySelector("#num2").value );
function handleStuff(evt) {
if (evt.target.nodeName.toLowerCase() === "button") {
if (evt.target.id === "combine") {
numbers = combine(
+document.querySelector("#num1").value,
+document.querySelector("#num2").value );
if (numbers.combined > Number.MAX_SAFE_INTEGER) {
log (`${numbers.combined} too large, unraveled will be unreliable`);
} else {
log (`Combined ${numbers.a} and ${numbers.b} to ${numbers.combined}`);
}
} else {
log(`${numbers.combined} unraveled to ${numbers.unraveled}`);
}
}
}
})();
input[type=number] {width: 100px;}
<p>
<input type="number" id="num1"
value="12315" min="1"> first number
</p>
<p>
<input type="number" id="num2"
value="231091" min="1"> second number
</p>
<p>
<button id="combine">combine</button>
<button id="unravel">unravel</button>
</p>
<pre id="result"></pre>
Note: #RallFriedl inspired this answer
JSFiddle
Yes, you can, assuming your two integers don't contain more information than the one integer can handle.
Let's assume your tasks and sub tasks are in the range 1..255. Then you can encode
combined = (task * 256) + subtask
And decode
task = combined / 256
subtask = combined % 256
At first, you don't have to convert an integer to hexadecimal to do this. An integer is a value and decimal, hexadecimal or binary is a representation to visualize that value. So all you need is integer arithmetics to achieve your goal.
According to this answer the maximum allowed integer number in javascript would be 9007199254740991. If you write this down in binary you'll get 53 ones, which means there are 53 bits available to store within an integer. Now you can split up this into two or more smaller ranges as you need.
For example let's say you need to save three numbers, the first is always lower 4.294.967.296 (32-bit), the second always lower 65.536 (16-bit) and the third always lower 32 (5-bit). If you sum up all the bits of these three values, you'll get 53 bits which means it would perfectly match.
To pack all these values into one, all you need is to move them at the right bit position within the integer. In my example I'd like to let the 32 bit number on the lowest position, then the 16 bit number and at the highest position the 5 bit number:
var max32bitValue = 3832905829; // binary: 1110 0100 0111 0101 1000 0000 0110 0101
var max16bitValue = 47313; // binary: 1011 1000 1101 0001
var max5bitValue = 17; // binary: 1000 1
var packedValue = max32bitValue // Position is at bit 0, so no movement needed.
+ max16bitValue << 32 // Move it up next to the first number.
+ max5bitValue << 48; // Move it up next to the second number (32 + 16)
This single integer value can now be stored, cause is a perfectly valid javascript integer value, but for us it holds three values.
To get all three values out of the packed value, we have to pick the correct bits out of it. This involves two steps, first remove all unneeded bits on the lower side (by using shift right), then remove all unneeded bits on the higher side (by masking out):
var max32bitValueRead = packedValue & Math.pow(2, 32); // No bits on the lower side, just mask the higher ones;
var max16bitValueRead = (packedValue >> 32) & Math.pow(2, 16); // Remove first 32 bits and set all bits higher then 16 bits to zero;
var max5bitValueRead = (packedValue >> 48); // Remove first 48 bits (32 + 16). No higher bits there, so no mask needed.
So hope this helps to understand, how to put multiple integer values into one, if the ranges of these values don't exceed the maximum bit range. Depending on your needs you could put two values with 26 bits each into this or move the range like one 32 bit value and one 21 bit value or a 48 bit value and a 5 bit value. Just be sure what your maximum value for each one could be and set the width accordingly (maybe add one to three bits, just to be sure).
I wouldn't suggest using hexadecimal if you can not have 2 sequential numbers. Try converting to an ASCII character and then back. So if you wanted to send:
{ 'task': 21 }
You could set the 21 to a character like:
var a = 55; var b = String.fromCharCode(a); var send2 = { 'task': b };
And to convert it back it would be: var res = { 'task': b }; var original = res.task.charCodeAt();

Random Hex Color

This is the javascript to generate a random hex color:
'#'+(Math.random()*0xFFFFFF<<0).toString(16);
could anyone talk me through it?
I understand how the Math.random works (as well as the to String at the end), but I don't understand the syntax after that. Questions I have:
How can Math.random() multiplied by F output a number?
What does the <<0 mean?
What does the parameter of 16 on toString mean? (does it mean no
more than 16 letters?)
Would really appreciate any help with this.
Thanks,
Raph
It looks like you picked this up on codegolf.
How can Math.random() multiplied by F output a number?
It is not multiplied by F. 0xFFFFFF is converted to 16777215, as 0xFFFFFF is just the hexadecimal way of writing 16777215.
What does the <<0 mean?
<< is a bitshift operator. <<0 shifts all bits 0 places to the left (filler: 0). This doesn't make any sense though. In this case it just deletes any decimal places.
What does the parameter of 16 on toString mean? (does it mean no more than 16 letters?)
The 16 is the parameter for the numeral system. (2 is binary, 8 is octal, 10 is decimal/normal, 16 is hexadecimal, etc.).
The best way to generate random HEX color:
It contains of tow functions:
The fest one picks a random hex number.
and the second one creates an array with hex values.
// Returns one possible value of the HEX numbers
function randomHex() {
var hexNumbers = [
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
'A',
'B',
'C',
'D',
'E',
'F'
]
// picking a random item of the array
return hexNumbers[Math.floor(Math.random() * hexNumbers.length)];
}
// Genarates a Random Hex color
function hexGenerator() {
hexValue = ['#'];
for (var i = 0; i < 6; i += 1) {
hexValue.push(randomHex());
}
return hexValue.join('');
}
// print out the random HEX color
document.write(hexGenerator());
good luck

Decomposing a value into results of powers of two

Is it possible to get the integers that, being results of powers of two, forms a value?
Example:
129 resolves [1, 128]
77 resolves [1, 4, 8, 64]
I already thought about using Math.log and doing also a foreach with a bitwise comparator. Is any other more beautiful solution?
The easiest way is to use a single bit value, starting with 1 and shift that bit 'left' until its value is greater than the value to check, comparing each bit step bitwise with the value. The bits that are set can be stored in an array.
function GetBits(value) {
var b = 1;
var res = [];
while (b <= value) {
if (b & value) res.push(b);
b <<= 1;
}
return res;
}
console.log(GetBits(129));
console.log(GetBits(77));
console.log(GetBits(255));
Since shifting the bit can be seen as a power of 2, you can push the current bit value directly into the result array.
Example
You can adapt solutions from other languages to javascript. In this SO question you'll find some ways of solving the problem using Java (you can choose the one you find more elegant).
decomposing a value into powers of two
I adapted one of those answers to javascript and come up with this code:
var powers = [], power = 0, n = 129;// Gives [1,128] as output.
while (n != 0) {
if ((n & 1) != 0) {
powers.push(1 << power);
}
++power;
n >>>= 1;
}
console.log(powers);
Fiddle
Find the largest power of two contained in the number.
Subtract from the original number and Add it to list.
Decrement the exponent and check if new 2's power is less than the number.
If less then subtract it from the original number and add it to list.
Otherwise go to step 3.
Exit when your number comes to 0.
I am thinking of creating a list of all power of 2 numbers <= your number, then use an addition- subtraction algorithm to find out the group of correct numbers.
For example number 77:
the group of factors is { 1,2,4,8,16,32,64} [ 64 is the greatest power of 2 less than or equal 77]
An algorithm that continuously subtract the greatest number less than or equal to your number from the group you just created, until you get zero.
77-64 = 13 ==> [64]
13-8 = 7 ==> [8]
7-4 = 3 ==> [4]
3-2 = 1 ==> [2]
1-1 = 0 ==> [1]
Hope you understand my algorithm, pardo my bad english.
function getBits(val, factor) {
factor = factor || 1;
if(val) {
return (val % 2 ? [factor] : []).concat(getBits(val>>1, factor*2))
}
return [];
}
alert(getBits(77));

Categories