Random number generator, what's wrong with my approach/statistics? [JS] - javascript

First of all, what I want to know is if I am doing a systematic fault or am I messing up with the math, or do you have any ideas what could be wrong?
I was trying to write a little random number generator which numbers can be influenced / verified by the user (provably fair). The generated number is between 4096 and 65535. I simulated the function 100,000 times and get some strange statistics (Or am I thinking wrong??).
Why is the chance that the number is under 8000 around ~50%. Shouldn't it be 50% around the middle of the number range (~30700)?
Here is the output of the simulation:
< 65536 : 100000 Times :100%
< 60000 : 91813 Times :91.813%
< 56000 : 86406 Times :86.406%
< 52000 : 81334 Times :81.334%
< 48000 : 76743 Times :76.743%
< 32768 : 62356 Times :62.356%
< 32000 : 61748 Times :61.748%
< 30719 : 60860 Times :60.86%
< 24000 : 56628 Times :56.628%
< 16000 : 52871 Times :52.871%
< 12000 : 51540 Times :51.54%
< 8000 : 50447 Times :50.447%
< 6000 : 36003 Times :36.003%
< 5096 : 21583 Times :21.583%
< 4608 : 11714 Times :11.714%
< 4250 : 3674 Times :3.674%
< 4100 : 100 Times :0.1%
< 4096 : 0 Times :0%
A little more details on the function I wrote:
I am generating two hashes. One is the userhash and the other is the serverhash. Both of these have a format like e.g.:
Server =3CDC3C8C97DEE62169B2C403BB2B6B501C1B0A0BD8015699B47DA67789C3F628
User =CF27CC73E33E0AC1DA5239DE8DAF94044D89B8636DA90F4CE510E652C8AC7F54
(The Userhash, is generated by a unique ID. The Serverhash is generated by taking a random number (standard function: math.random() )and a timestamp and then HMAC-SHA-512 them.)
To get my "random" number, i take both (user and server) hashes and add them as hexadecimal numbers (userhash + serverhash = result). Then I take the result and cut everything except the first 4 digits. (E.g result = CF27)
After that, I convert it to decimal again.
The smallest number I can get from this should be in Hex 1000 (dec=4096), the biggest in Hex FFFF (dec=65535). That means my random number should be in a Range of 4096 - 65535.
Code Snippets:
//Function for getting a dec number from two hashes
function test_Rand(SERVER_SECRET, CLIENT_SECRET){
var client_hash = require('crypto'),
text = CLIENT_SECRET,
key = SERVER_SECRET
// create hash
var hash = client_hash.createHmac('sha512', key);
hash.update(text);
var clientRollAsHex = hash.digest('hex')
var serverRollAsHex = SERVER_SECRET;
//Add the numbers in Hex
var roll_hex = addHex(clientRollAsHex, serverRollAsHex);
//Cut the hex String
roll_hex = roll_hex.substring(0,4);
// Make INT
var roll_dec = parseInt(roll_hex, 16);
return roll_dec;
}
//Function for Hex-adding
function addHex(c1, c2) {
var hexStr = (parseInt(c1, 16) + parseInt(c2, 16)).toString(16);
while (hexStr.length < 6) { hexStr = '0' + hexStr; } // Zero pad.
return hexStr;
}
The SERVER_SECRET comes from the following func.
var secret = function() {
var r1 = Math.random()*10000000 + Math.floor(Date.now() / 1000);
var r2 = Math.random()*1000000 + Math.floor(Date.now() / 2000); //That does not make much sense
var new_hash = require('crypto');
var text = r1;
var key = r2;
// create hahs
var r_hash = new_hash.createHmac('sha512', key.toString());
r_hash.update(text.toString());
var retrn = r_hash.digest('hex');
return retrn;
}

It's because you are taking the first four digits that you get a skewed result.
For 50% of the numbers you will get a result that is 65 digits long instead of 64, and the first digit is 1. For example adding the two numbers in your example:
3CDC3C8C9...
CF27CC73E...
= 10C0409007...
Taking the first four digits from the result gives you 10C0. As you see from your result, there are a lot of numbers between 1000 (4096) and 1FFF (8191). Most of those are numbers where the result is 65 digits instead of 64.
If you instead take any four digits at a specific position (counter from the right), for example the last four digits, you will get a pretty even distribution of numbers between 0000 and FFFF.

A much simplified version of your design:
var a=Math.floor((Math.random() * 10));
var b=Math.floor((Math.random() * 10));
What is the range of a+b? 0-18
Now take only the first digit of the result. Then 0-9 would still be their original value *but 10-18 becomes 1.
To get the result you want, you need to remove the first digit for cases 10-18.

Related

reduction of complexity numbers procedure

I'm looking for a solution to my problem
if I have numbers
var first = 14:1
var next = 13:8
therefore, the console should give a result
console.log(first_result) // 141
console.log(next_result) // 141
and I want the numbers counted like 141 in the result to be
simply if there is an example
13:8 if both digits are the last, 3 and 8 are bigger than ten, then turn the tens and turn and insert into the previous number and leave the rest at the end
so 13:8 becomes 141
If you are starting with strings, then you just simply split the string on : to get your 2 numbers.
To get the last digit, you can simply use x % 10. Then just add the numbers and see what happens.
let value = '13:8',
nums = value.split(':').map(Number),
last_digits = nums.map(x => x % 10),
// or last_digits.reduce((x,y) => x+y, 0)
sum = last_digits[0] + last_digits[1],
result;
if (sum > 10) {
nums[0]++;
nums[1] = sum - 10; // or, probably sum % 10
}
result = nums.join('');
console.log(result);

How to generate a random number , the length of the number needs to be 21 and should be prefixed with "01" in Postman

I am using the code below to generate a random number. Result output should be a length of 21 and with prefix starting with "01"
postman.setGlobalVariable('RandomOrderId', "01"+ Math.floor(Math.random() * 1234567890123456789));
However, sometimes it generates output with a length of 20, 19 and so on. How do I make sure it always generate a random number with length 21 and prefix as "01"?
Math.random gives you a random number between 0 and 1, multiplying that with a million gives you something between zero and a million. If you want to allow leading numbers you could convert the number to a string and add the necessary amount of leading zeroes, if that is possible in your case. Else, you could generate 21 random numbers between 0 and 9 and combine them to a random huge number (which could also have leading zeroes).
Code could look like this:
var s = "01";
for(var i = 0; i < 21; i++) {
s = s + Math.floor(Math.random() * 10);
}
console.log(s);
Use the below
postman.setGlobalVariable('RandomOrderId', "01"+ Math.floor(1000000000000000000 + Math.random() * 1000000000000000000));
Verify using the below
function getRandomInt() {
return ( "01" + Math.floor(1000000000000000000 + Math.random() * 1000000000000000000));
}
console.log(getRandomInt());
console.log(getRandomInt());
console.log(getRandomInt());
console.log(getRandomInt());
console.log(getRandomInt());
Try injecting this JS:
var len = 21;
parseInt((Math.random() * 20 + 1) * Math.pow(20,len-1), 20);
You could also use the Lodash _.random() method within Postman. Set the lower and upper values for the range and it will return a 19 digit number between those values. The 01 prefix can be added straight to the global value.
const lowerLimit = 1000000000000000000
const upperLimit = 9999999999999999999
pm.globals.set("randomNumber", `01${_.random(lowerLimit,upperLimit)}`)
Just a different way to get the same result as the accepted answer.

Pick random combination from 194481 possibilities

I have a file of 194481 permutations for
0,1,2,3,4,5,6,...,21
which looks like this;
[0,0,0,0],[0,0,0,1],[0,0,0,2],[0,0,0,3],[0,0,0,4],[0,0,0,5],[0,0,0,6],[0,0,0,7],[0,0,0,8],[0,0,0,9],[0,0,0,10],[0,0,0,11],[0,0,0,12],[0,0,0,13],[0,0,0,14],[0,0,0,15],[0,0,0,16],[0,0,0,17],[0,0,0,18],[0,0,0,19],[0,0,0,20],[0,0,1,0],[0,0,1,1],[0,0,1,2],[0,0,1,3],[0,0,1,4],[0,0,1,5],[0,0,1,6],[0,0,1,7],[0,0,1,8],[0,0,1,9],[0,0,1,10],[0,0,1,11],[0,0,1,12],[0,0,1,13],[0,0,1,14],[0,0,1,15],[0,0,1,16],[0,0,1,17],[0,0,1,18],[0,0,1,19],[0,0,1,20],[0,0,2,0],[0,0,2,1],[0,0,2,2],[0,0,2,3],[0,0,2,4],[0,0,2,5],[0,0,2,6],[0,0,2,7],[0,0,2,8],[0,0,2,9],[0,0,2,10],[0,0,2,11],[0,0,2,12],[0,0,2,13],[0,0,2,14],[0,0,2,15],[0,0,2,16],[0,0,2,17],[0,0,2,18],[0,0,2,19],[0,0,2,20],[0,0,3,0],[0,0,3,1],[0,0,3,2],[0,0,3,3],[0,0,3,4],[0,0,3,5],[0,0,3,6],[0,0,3,7],[0,0,3,8],[0,0,3,9],[0,0,3,10],[0,0,3,11],[0,0,3,12],[0,0,3,13],[0,0,3,14],[0,0,3,15],[0,0,3,16],[0,0,3,17],[0,0,3,18],[0,0,3,19],[0,0,3,20],[0,0,4,0],[0,0,4,1],[0,0,4,2],[0,0,4,3],[0,0,4,4],[0,0,4,5],[0,0,4,6],[0,0,4,7],[0,0,4,8],[0,0,4,9],[0,0,4,10],[0,0,4,11],[0,0,4,12],[0,0,4,13],[0,0,4,14],[0,0,4,15],[0,0,4,16],[0,0,4,17],[0,0,4,18],[0,0,4,19],[0,0,4,20],[0,0,5,0],[0,0,5,1],[0,0,5,2],[0,0,5,3],[0,0,5,4],[0,0,5,5],[0,0,5,6],[0,0,5,7],[0,0,5,8],[0,0,5,9],[0,0,5,10],[0,0,5,11],[0,0,5,12],[0,0,5,13],[0,0,5,14],[0,0,5,15],[0,0,5,16],[0,0,5,17],[0,0,5,18],[0,0,5,19],[0,0,5,20],[0,0,6,0],[0,0,6,1],[0,0,6,2],[0,0,6,3],[0,0,6,4],[0,0,6,5],[0,0,6,6],[0,0,6,7],[0,0,6,8],[0,0,6,9],[0,0,6,10],[0,0,6,11],[0,0,6,12],[0,0,6,13],[0,0,6,14],[0,0,6,15],[0,0,6,16],[0,0,6,17],[0,0,6,18],[0,0,6,19],[0,0,6,20],[0,0,7,0],[0,0,7,1],[0,0,7,2],[0,0,7,3],[0,0,7,4],[0,0,7,5],[0,0,7,6],[0,0,7,7],[0,0,7,8],[0,0,7,9],[0,0,7,10],[0,0,7,11],[0,0,7,12],[0,0,7,13],[0,0,7,14],[0,0,7,15],[0,0,7,16],[0,0,7,17],[0,0,7,18],[0,0,7,19],[0,0,7,20],[0,0,8,0],[0,0,8,1],[0,0,8,2],[0,0,8,3],[0,0,8,4],[0,0,8,5],[0,0,8,6],[0,0,8,7],[0,0,8,8],[0,0,8,9],[0,0,8,10],[0,0,8,11],[0,0,8,12],[0,0,8,13],[0,0,8,14],[0,0,8,15],[0,0,8,16],[0,0,8,17],[0,0,8,18],[0,0,8,19],[0,0,8,20],[0,0,9,0],[0,0,9,1],[0,0,9,2],[0,0,9,3],[0,0,9,4],[0,0,9,5],[0,0,9,6],[0,0,9,7],[0,0,9,8],[0,0,9,9],[0,0,9,10],[0,0,9,11],[0,0,9,12],[0,0,9,13],[0,0,9,14],[0,0,9,15],[0,0,9,16],[0,0,9,17],[0,0,9,18],[0,0,9,19],[0,0,9,20],[0,0,10,0],[0,0,10,1],[0,0,10,2],[0,0,10,3],[0,0,10,4],[0,0,10,5],[0,0,10,6],[0,0,10,7],[0,0,10,8],[0,0,10,9],[0,0,10,10],[0,0,10,11],[0,0,10,12],[0,0,10,13],[0,0,10,14],[0,0,10,15],[0,0,10,16],[0,0,10,17],[0,0,10,18],[0,0,10,19],[0,0,10,20],[0,0,11,0],[0,0,11,1],[0,0,11,2],[0,0,11,3],[0,0,11,4],[0,0,11,5],[0,0,11,6],[0,0,11,7],[0,0,11,8],[0,0,11,9],[0,0,11,10],[0,0,11,11],[0,0,11,12],[0,0,11,13],[0,0,11,14],[0,0,11,15],[0,0,11,16],[0,0,11,17],[0,0,11,18],[0,0,11,19],[0,0,11,20],[0,0,12,0],[0,0,12,1],[0,0,12,2],[0,0,12,3],[0,0,12,4],[0,0,12,5],[0,0,12,6],[0,0,12,7],[0,0,12,8],[0,0,12,9],[0,0,12,10],[0,0,12,11],[0,0,12,12],[0,0,12,13],[0,0,12,14],[0,0,12,15],[0,0,12,16],[0,0,12,17],[0,0,12,18],[0,0,12,19],[0,0,12,20],[0,0,13,0],[0,0,13,1],[0,0,13,2],[0,0,13,3],[0,0,13,4],[0,0,13,5],[0,0,13,6],[0,0,13,7],[0,0,13,8],[0,0,13,9],[0,0,13,10],[0,0,13,11],[0,0,13,12],[0,0,13,13],[0,0,13,14],[0,0,13,15],[0,0,13,16],[0,0,13,17],[0,0,13,18],[0,0,13,19],[0,0,13,20],[0,0,14,0],[0,0,14,1],[0,0,14,2],[0,0,14,3],[0,0,14,4],[0,0,14,5],[0,0,14,6],[0,0,14,7],[0,0,14,8],[0,0,14,9],[0,0,14,10],[0,0,14,11],[0,0,14,12],[0,0,14,13],[0,0,14,14],[0,0,14,15],[0,0,14,16],[0,0,14,17],[0,0,14,18],[0,0,14,19],[0,0,14,20],[0,0,15,0],[0,0,15,1],[0,0,15,2],[0,0,15,3],[0,0,15,4],[0,0,15,5],[0,0,15,6],[0,0,15,7],[0,0,15,8],[0,0,15,9],[0,0,15,10],[0,0,15,11],[0,0,15,12],[0,0,15,13],[0,0,15,14],[0,0,15,15],[0,0,15,16],[0,0,15,17],[0,0,15,18],[0,0,15,19],[0,0,15,20],[0,0,16,0],[0,0,16,1],[0,0,16,2],[0,0,16,3],[0,0,16,4],[0,0,16,5],[0,0,16,6],[0,0,16,7],[0,0,16,8],[0,0,16,9],[0,0,16,10],[0,0,16,11],[0,0,16,12],[0,0,16,13],[0,0,16,14],[0,0,16,15],[0,0,16,16],[0,0,16,17],[0,0,16,18],[0,0,16,19],[0,0,16,20],[0,0,17,0],[0,0,17,1],[0,0,17,2],[0,0,17,3],[0,0,17,4],[0,0,17,5],[0,0,17,6],[0,0,17,7],[0,0,17,8],[0,0,17,9],[0,0,17,10],[0,0,17,11],[0,0,17,12],[0,0,17,13],[0,0,17,14],[0,0,17,15],[0,0,17,16],[0,0,17,17]... etc.
It ends at [20,20,20,20].
I need to pick 50 combinations from the file and assign it to a variable so it would be like
var combinationsArr = [
[0,0,17,9],[0,0,17,10],[0,0,17,11],[0,0,17,12]
]; //BUT 50 of them
it's okay if it is just in order like [0,0,0,0],[0,0,0,1],[0,0,0,2],[0,0,0,3],[0,0,0,4],[0,0,0,5],[0,0,0,6],[0,0,0,7],[0,0,0,8],[0,0,0,9],[0,0,0,10],[0,0,0,11],[0,0,0,12] and doesn't have to be super random like [1,2,3,4],[9,12,13,15],[20,12,6,7]
as long as it is able to pick 50 of them.
I am doing this because 194481 combinations are a lot and makes my program carsh. so I just decided i'll put it in a text file and pick random points from the text file like from [0,0,0,1] to [0,0,0,50] OR
from [0,1,0,0] to [0,1,0,49] if that's possible.
because i have to generate a random combination. I have another array of combinations which are not supposed to be generated. Let's call it notAllowedArr.
var notAllowedArr = [
[0,0,17,9],[0,0,17,12]
];
I am thinking, i'll just generate 50 combinations and remove the ones listed in notAllowedArr then pick one from combinationsArr as the final result. I will still have to find code to remove those from combinationsArr but the result should be like.
var combinationsArr = [[0,0,17,10],[0,0,17,11]];
then i'll have a code to pick a random value from combinationsArr.
example. combinationsArr[0].
so the final result would be; [0,0,17,10]
Does anyone have a better solution?
If I understand correctly, you need to pick one random combination, which is not present in a list of forbidden combinations.
You can consider a combination of four numbers from 0 to 20 as a number from 0 to 194480 in base-21 notation. So instead of having to store all combinations in a file, we just pick a random number and convert it to base-21.
To choose a random number in a range where some values are forbidden, choose a number in the range from 0 to the maximum minus the number of forbidden values; then iterate over the forbidden values from small to large, and increment the random number every time you find a smaller or equal forbidden value.
This will make sure that every combination has the same probability of being chosen, and avoids the possibility of repeatedly choosing a forbidden combination.
function randomBase21(skip) {
var dec = [], result = [], num;
// CONVERT FORBIDDEN COMBINATIONS FROM BASE-21 TO DECIMAL AND SORT
for (var i = 0; i < skip.length; i++) {
dec[i] = skip[i][0] * 9261 + skip[i][1] * 441 + skip[i][2] * 21 + skip[i][3];
}
dec.sort(function(a, b){return a - b});
// GENERATE RANDOM NUMBER FROM 0 TO MAX - NUMBER OF FORBIDDEN COMBINATIONS
num = Math.floor(Math.random() * (194481 - skip.length));
// INCREMENT RANDOM NUMBER FOR EVERY SMALLER FORBIDDEN COMBINATION
for (var i = 0; i < skip.length && num >= dec[i]; i++) {
++num;
}
// CONVERT RANDOM NUMBER TO FOUR BASE-21 DIGITS
for (var i = 3; i >= 0; i--, num /= 21) {
result[i] = Math.floor(num % 21);
}
return result;
}
var notAllowed = [[0,0,17,9],[0,0,17,12],[20,19,17,12],[15,16,17,12]];
document.write(randomBase21(notAllowed));
Something like this should work (off the top of my head and not tested/debugged):
var samples = new Array();
for(var index = 0; index < 50; index++) {
samples.push(generatePermutation());
}
function generatePermutation() {
var result = [Math.floor(Math.random() * 20) + 1,
Math.floor(Math.random() * 20) + 1,
Math.floor(Math.random() * 20) + 1,
Math.floor(Math.random() * 20) + 1];
}
I just thought of a better way.
I think I will make a function that generates a random combination.
Then check if it exists in notAllowedArr. If it exists, it will generate another one. If not then that will return that combination :D
I think this will work faster ^^;

Find out how many thousands and hundreds and tens are there in a amount

I am having a asp application and in that amount column is there. I need to find out how many thousands and hundreds and tens are there in that amount
For example
if i am having amount as 3660 means
1000's - 3
100's - 6
10's - 6
like this i need
Can any body help me
The simple answer is to divide the number by 1000 whatever is the quotient that is the number of 1000's in the amount. Then divide the remainder with the 100's the quotient will be the number of 100's. And then again divide the remainder with 10, the quotient will be the number of 10's
Something like this:
quotient = 3660 / 1000; //This will give you 3
remainder = 3660 % 1000; //This will give you 660
Then,
quotient1 = remainder/ 100; //This will give you 6
remainder1 = remainder % 100; //This will give you 60
And finally
quotient2 = remainder1 / 10; //This will give you 6
Is it not easier to use type coercion and change the data type to string?
Then you can easily check the value by checking the value at selected index position,
var number = 1234;
number2 = new String(number);
var thousands = number2[0];
var hundreds = number2[1];
and so on....
It may not be usable in what you're doing, it was for me :)
If the "javascript" tag is the correct one, then you've already gotten some answers. If the "asp-classic" tag is actually the correct one, then chances are your scripting language is VBScript, not Javascript.
Did you just pick multiples of 10 as an example, or is that the actual multiple you're looking for? Because if it's the latter, then all you need to do is split the number into digits — that's what the base 10 number system means, after all.
Function SplitNum(theNum)
dim L, i, s, n
n = CStr(theNum)
L = Len(n)
s = ""
for i = 1 to 3
if s <> "" then s = "," & s
if i >= L then
s = "0" & s
else
s = Left(Right(n,i+1),1) & s
end if
next
if L > 4 then s = left(n,L-4) & s
SplitNum = s
End Function
If your actual divisors are something other than multiples of 10, you'll need to do arithmetic. The integer division operator in VBScript is \. (Integer division is basically the "opposite" of the modulus function.)
Function GetMultiples(theNum)
dim q, r
q = theNum \ 1000 & ","
r = theNum Mod 1000
q = q & r \ 100 & ","
r = r Mod 100
q = q & r \ 10
GetMultiples = q
End Function
Try this out...
Here is a fiddle that demonstrates how to use the output..
http://jsfiddle.net/Villarrealized/L3AxZ/1/
function getMultiplesOfTen(number){
number = parseInt(number);
if(typeof(number)!=="number") return number;
var result = {};
(function breakDown(num){
if(isNaN(num))return num;//if it's invalid return
if(num<=0)return false;
num = num.toFixed(0);//get rid of decimals
var divisor = Math.pow(10,num.length-1),//ex. when num = 300, divisor = 100
quotient = Math.floor(num/divisor);
result[divisor]=quotient;//add it to our object
breakDown(num % divisor);//break down the remainder
})(number);
//return result as an object
return result;
}
This function will return an object with the multiple of ten as the key and the number as the value
ex. getMultiplesOfTen(150)=={100:1,10:5} == 1 multiple of 100 and 5 multiples of 10.
Let's say we have the number 7354. To find the thousands:
variable a = 7354 / 1000
variable b = a % 10
The number which is stored in variable b now is the number if the thousands.
To find the hundreds:
variable c = 7354 / 100
variable d = a % 10
The number which is stored in variable d now is the number if the hundreds.
To find the tens:
variable e = 7354 / 10
variable f = a % 10
The number which is stored in variable f now is the number if the tens.
To find the ones:
7354 % 10
This works for every number in the place of 7354, even for bigger numbers than 7354.
The first digit in the quotient of 1,592÷64
1
is in the Choose... ones tens hundreds thousands place.
Decide where the first digit of the quotient should be placed. Do not complete the division.
The first digit of the quotient for 2,370÷24
2,370÷24
should be in the Choose... ones tens hundreds thousands place
2021 version here:
Cast your number as a string, spread it and reverse it like so:
x = 1234
x = [...x.toString()].reverse() // [4, 3, 2, 1]
thous = x[3] // 1
hunds = x[2] // 2
tens = x[1] // 3
units = x[0] // 4
y = [...x.toString()].reverse()[3] // 1 because 1000 has 3 zeros
I suppose you can use some fancy system of powers of 10 to get those indexes. So let's do exactly that and get #Villarrealized 15 lines of 2013 code condensed into just a few lines of 2021 code:
function placeValues(someNumber = 1234) {
x = [...someNumber.toString()].reverse().reduce((p, c, i) => {
p[10**i] = c;
return p;
}, {});
return x; // {1000:1, 100:2, 10:3, 1:4}
}

Writing a function in javascript that is the inverse of another

I'm trying to write a function that is the inverse of the function below.
So that I can get the output from the function foo and generate it's input parameter.
I'm not entirely sure if it's possible.
function foo(str){
var hexMap = {
"0":0,
"1":1,
"2":2,
"3":3,
"4":4,
"5":5,
"6":6,
"7":7,
"8":8,
"9":9,
"A":10,
"B":11,
"C":12,
"D":13,
"E":14,
"F":15
};
var charList = [];
str = str.toUpperCase();
for (var i = 0; i < str.length; i += 2) {
charList.push(hexMap[str.charAt(i)] * 16 + hexMap[str.charAt(i + 1)]);
}
charList.splice(0, 8);
charList.splice(0, 123);
var sliceEnd = charList[0] + charList[1] * 256;
charList.splice(0, 4);
charList = charList.slice(0, sliceEnd);
return charList;
}
Your function takes in a string that is hopefully a hexadecimal string using only the characters [0-9a-fA-F]. Then it makes an array where every two hex characters are converted to a decimal integer between 0 and 255. Then the function immediately throws away the first 131 elements from this array. This means that the first 262 characters on your string have no impact on the output of the function (The first 262 characters can be any characters).
Then there is this line:
var sliceEnd = charList[0] + charList[1] * 256;
sliceEnd becomes a number between 0 and 65535 (the maximum size of the resulting array). Based on the characters at indices 262 - 265 in the input string. (Two two digit hex values converted to two integers. The value at position 264 is multiplied by 256 and added to the value at position 262).
Then the resulting array contains the integers converted using the same method from the characters from position 270 to 270 + sliceEnd*2.
MSN is correct that this function is not 1 to 1 and therefore not mathematically invertible, but you can write a function which given an array of less than 65536 integers between 0 and 255 can generate an input string for foo which will give back that array. Specifically the following function will do just that:
function bar(arr){
var sliceEnd = arr.length;
var temp = '00' + (sliceEnd & 255).toString(16);
var first = temp.substring(temp.length - 2);
temp = '00' + Math.floor(sliceEnd/256).toString(16);
var second = temp.substring(temp.length - 2);
var str = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' + first + second + '0000';
for(var i = 0; i < arr.length; i++){
temp = '00' + arr[i].toString(16);
str += temp.substring(temp.length - 2);
}
return str;
}
This gives you the property that foo(bar(x)) === x (if x is an array of less than 65536 integers between 0 and 255 as stated previously), but not the property bar(foo(x)) === x because as MSN pointed out that property is impossible to achieve for your function.
EG. bar([17,125,12,11]) gives the string:
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000117dcb" which if you give as input to your function foo you get back the original array: [17,125,12,11], but there are many other inputs (at least 268 of those 0's can be any other of the values in [0-9a-fA-F], and the 04 can be anything greater than 04 which means 22^268*(255 - 4) different strings multiplied by a bit more since that only takes into account either lower case or capitals but not both when multiplying by 255 - 4. regardless 22^268 is a ridiculous number of inputs for one output anyways, and that's ignoring the fact that their are an infinite amount of strings which begin with the string above and have any other hexadecimal string appended to them which will give the same output from foo because of the sliceEnd variable.
That function is not a 1 to 1 function, i.e., many inputs will generate the same output.

Categories