Is it possible to seed the random number generator (Math.random) in JavaScript?
No, it is not possible to seed Math.random(). The ECMAScript specification is intentionally vague on the subject, providing no means for seeding nor require that browsers even use the same algorithm. So such a function must be externally provided, which thankfully isn't too difficult.
I've implemented a number of good, short and fast Pseudorandom number generator (PRNG) functions in plain JavaScript. All of them can be seeded and provide high quality numbers. These are not intended for security purposes--if you need a seedable CSPRNG, look into ISAAC.
First of all, take care to initialize your PRNGs properly. To keep things simple, the generators below have no built-in seed generating procedure, but accept one or more 32-bit numbers as the initial seed state of the PRNG. Similar or sparse seeds (e.g. a simple seed of 1 and 2) have low entropy, and can cause correlations or other randomness quality issues, sometimes resulting in the output having similar properties (such as randomly generated levels being similar). To avoid this, it is best practice to initialize PRNGs with a well-distributed, high entropy seed and/or advancing past the first 15 or so numbers.
There are many ways to do this, but here are two methods. Firstly, hash functions are very good at generating seeds from short strings. A good hash function will generate very different results even when two strings are similar, so you don't have to put much thought into the string. Here's an example hash function:
function cyrb128(str) {
let h1 = 1779033703, h2 = 3144134277,
h3 = 1013904242, h4 = 2773480762;
for (let i = 0, k; i < str.length; i++) {
k = str.charCodeAt(i);
h1 = h2 ^ Math.imul(h1 ^ k, 597399067);
h2 = h3 ^ Math.imul(h2 ^ k, 2869860233);
h3 = h4 ^ Math.imul(h3 ^ k, 951274213);
h4 = h1 ^ Math.imul(h4 ^ k, 2716044179);
}
h1 = Math.imul(h3 ^ (h1 >>> 18), 597399067);
h2 = Math.imul(h4 ^ (h2 >>> 22), 2869860233);
h3 = Math.imul(h1 ^ (h3 >>> 17), 951274213);
h4 = Math.imul(h2 ^ (h4 >>> 19), 2716044179);
return [(h1^h2^h3^h4)>>>0, (h2^h1)>>>0, (h3^h1)>>>0, (h4^h1)>>>0];
}
Calling cyrb128 will produce a 128-bit hash value from a string which can be used to seed a PRNG. Here's how you might use it:
// Create cyrb128 state:
var seed = cyrb128("apples");
// Four 32-bit component hashes provide the seed for sfc32.
var rand = sfc32(seed[0], seed[1], seed[2], seed[3]);
// Only one 32-bit component hash is needed for mulberry32.
var rand = mulberry32(seed[0]);
// Obtain sequential random numbers like so:
rand();
rand();
Note: If you want a slightly more robust 128-bit hash, consider MurmurHash3_x86_128, it's more thorough, but intended for use with large arrays.
Alternatively, simply choose some dummy data to pad the seed with, and advance the generator beforehand a few times (12-20 iterations) to mix the initial state thoroughly. This has the benefit of being simpler, and is often used in reference implementations of PRNGs, but it does limit the number of initial states:
var seed = 1337 ^ 0xDEADBEEF; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
var rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (var i = 0; i < 15; i++) rand();
Note: the output of these PRNG functions produce a positive 32-bit number (0 to 232-1) which is then converted to a floating-point number between 0-1 (0 inclusive, 1 exclusive) equivalent to Math.random(), if you want random numbers of a specific range, read this article on MDN. If you only want the raw bits, simply remove the final division operation.
JavaScript numbers can only represent whole integers up to 53-bit resolution. And when using bitwise operations, this is reduced to 32. Modern PRNGs in other languages often use 64-bit operations, which require shims when porting to JS that can drastically reduce performance. The algorithms here only use 32-bit operations, as it is directly compatible with JS.
Now, onward to the the generators. (I maintain the full list with references and license info here)
sfc32 (Simple Fast Counter)
sfc32 is part of the PractRand random number testing suite (which it passes of course). sfc32 has a 128-bit state and is very fast in JS.
function sfc32(a, b, c, d) {
return function() {
a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0;
var t = (a + b) | 0;
a = b ^ b >>> 9;
b = c + (c << 3) | 0;
c = (c << 21 | c >>> 11);
d = d + 1 | 0;
t = t + d | 0;
c = c + t | 0;
return (t >>> 0) / 4294967296;
}
}
You may wonder what the | 0 and >>>= 0 are for. These are essentially 32-bit integer casts, used for performance optimizations. Number in JS are basically floats, but during bitwise operations, they switch into a 32-bit integer mode. This mode is processed faster by JS interpreters, but any multiplication or addition will cause it to switch back to a float, resulting in a performance hit.
Mulberry32
Mulberry32 is a simple generator with a 32-bit state, but is extremely fast and has good quality randomness (author states it passes all tests of gjrand testing suite and has a full 232 period, but I haven't verified).
function mulberry32(a) {
return function() {
var t = a += 0x6D2B79F5;
t = Math.imul(t ^ t >>> 15, t | 1);
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
}
I would recommend this if you just need a simple but decent PRNG and don't need billions of random numbers (see Birthday problem).
xoshiro128**
As of May 2018, xoshiro128** is the new member of the Xorshift family, by Vigna & Blackman (professor Vigna was also responsible for the Xorshift128+ algorithm powering most Math.random implementations under the hood). It is the fastest generator that offers a 128-bit state.
function xoshiro128ss(a, b, c, d) {
return function() {
var t = b << 9, r = a * 5; r = (r << 7 | r >>> 25) * 9;
c ^= a; d ^= b;
b ^= c; a ^= d; c ^= t;
d = d << 11 | d >>> 21;
return (r >>> 0) / 4294967296;
}
}
The authors claim it passes randomness tests well (albeit with caveats). Other researchers have pointed out that it fails some tests in TestU01 (particularly LinearComp and BinaryRank). In practice, it should not cause issues when floats are used (such as in these implementations), but may cause issues if relying on the raw lowest order bit.
JSF (Jenkins' Small Fast)
This is JSF or 'smallprng' by Bob Jenkins (2007), who also made ISAAC and SpookyHash. It passes PractRand tests and should be quite fast, although not as fast as sfc32.
function jsf32(a, b, c, d) {
return function() {
a |= 0; b |= 0; c |= 0; d |= 0;
var t = a - (b << 27 | b >>> 5) | 0;
a = b ^ (c << 17 | c >>> 15);
b = c + d | 0;
c = d + t | 0;
d = a + t | 0;
return (d >>> 0) / 4294967296;
}
}
No, it is not possible to seed Math.random(), but it's fairly easy to write your own generator, or better yet, use an existing one.
Check out: this related question.
Also, see David Bau's blog for more information on seeding.
NOTE: Despite (or rather, because of) succinctness and apparent elegance, this algorithm is by no means a high-quality one in terms of randomness. Look for e.g. those listed in this answer for better results.
(Originally adapted from a clever idea presented in a comment to another answer.)
var seed = 1;
function random() {
var x = Math.sin(seed++) * 10000;
return x - Math.floor(x);
}
You can set seed to be any number, just avoid zero (or any multiple of Math.PI).
The elegance of this solution, in my opinion, comes from the lack of any "magic" numbers (besides 10000, which represents about the minimum amount of digits you must throw away to avoid odd patterns - see results with values 10, 100, 1000). Brevity is also nice.
It's a bit slower than Math.random() (by a factor of 2 or 3), but I believe it's about as fast as any other solution written in JavaScript.
No, but here's a simple pseudorandom generator, an implementation of Multiply-with-carry I adapted from Wikipedia (has been removed since):
var m_w = 123456789;
var m_z = 987654321;
var mask = 0xffffffff;
// Takes any integer
function seed(i) {
m_w = (123456789 + i) & mask;
m_z = (987654321 - i) & mask;
}
// Returns number between 0 (inclusive) and 1.0 (exclusive),
// just like Math.random().
function random()
{
m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask;
m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask;
var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
result /= 4294967296;
return result;
}
Antti Sykäri's algorithm is nice and short. I initially made a variation that replaced JavaScript's Math.random when you call Math.seed(s), but then Jason commented that returning the function would be better:
Math.seed = function(s) {
return function() {
s = Math.sin(s) * 10000; return s - Math.floor(s);
};
};
// usage:
var random1 = Math.seed(42);
var random2 = Math.seed(random1());
Math.random = Math.seed(random2());
This gives you another functionality that JavaScript doesn't have: multiple independent random generators. That is especially important if you want to have multiple repeatable simulations running at the same time.
Please see Pierre L'Ecuyer's work going back to the late 1980s and early 1990s. There are others as well. Creating a (pseudo) random number generator on your own, if you are not an expert, is pretty dangerous, because there is a high likelihood of either the results not being statistically random or in having a small period. Pierre (and others) have put together some good (pseudo) random number generators that are easy to implement. I use one of his LFSR generators.
https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf
Combining some of the previous answers, this is the seedable random function you are looking for:
Math.seed = function(s) {
var mask = 0xffffffff;
var m_w = (123456789 + s) & mask;
var m_z = (987654321 - s) & mask;
return function() {
m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;
var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
result /= 4294967296;
return result;
}
}
var myRandomFunction = Math.seed(1234);
var randomNumber = myRandomFunction();
It's not possible to seed the builtin Math.random function, but it is possible to implement a high quality RNG in Javascript with very little code.
Javascript numbers are 64-bit floating point precision, which can represent all positive integers less than 2^53. This puts a hard limit to our arithmetic, but within these limits you can still pick parameters for a high quality Lehmer / LCG random number generator.
function RNG(seed) {
var m = 2**35 - 31
var a = 185852
var s = seed % m
return function () {
return (s = s * a % m) / m
}
}
Math.random = RNG(Date.now())
If you want even higher quality random numbers, at the cost of being ~10 times slower, you can use BigInt for the arithmetic and pick parameters where m is just able to fit in a double.
function RNG(seed) {
var m_as_number = 2**53 - 111
var m = 2n**53n - 111n
var a = 5667072534355537n
var s = BigInt(seed) % m
return function () {
return Number(s = s * a % m) / m_as_number
}
}
See this paper by Pierre l'Ecuyer for the parameters used in the above implementations:
https://www.ams.org/journals/mcom/1999-68-225/S0025-5718-99-00996-5/S0025-5718-99-00996-5.pdf
And whatever you do, avoid all the other answers here that use Math.sin!
To write your own pseudo random generator is quite simple.
The suggestion of Dave Scotese is useful but, as pointed out by others, it is not quite uniformly distributed.
However, it is not because of the integer arguments of sin. It's simply because of the range of sin, which happens to be a one dimensional projection of a circle. If you would take the angle of the circle instead it would be uniform.
So instead of sin(x) use arg(exp(i * x)) / (2 * PI).
If you don't like the linear order, mix it a bit up with xor. The actual factor doesn't matter that much either.
To generate n pseudo random numbers one could use the code:
function psora(k, n) {
var r = Math.PI * (k ^ n)
return r - Math.floor(r)
}
n = 42; for(k = 0; k < n; k++) console.log(psora(k, n))
Please also note that you cannot use pseudo random sequences when real entropy is needed.
Many people who need a seedable random-number generator in Javascript these days are using David Bau's seedrandom module.
Math.random no, but the ran library solves this. It has almost all distributions you can imagine and supports seeded random number generation. Example:
ran.core.seed(0)
myDist = new ran.Dist.Uniform(0, 1)
samples = myDist.sample(1000)
Here's the adopted version of Jenkins hash, borrowed from here
export function createDeterministicRandom(): () => number {
let seed = 0x2F6E2B1;
return function() {
// Robert Jenkins’ 32 bit integer hash function
seed = ((seed + 0x7ED55D16) + (seed << 12)) & 0xFFFFFFFF;
seed = ((seed ^ 0xC761C23C) ^ (seed >>> 19)) & 0xFFFFFFFF;
seed = ((seed + 0x165667B1) + (seed << 5)) & 0xFFFFFFFF;
seed = ((seed + 0xD3A2646C) ^ (seed << 9)) & 0xFFFFFFFF;
seed = ((seed + 0xFD7046C5) + (seed << 3)) & 0xFFFFFFFF;
seed = ((seed ^ 0xB55A4F09) ^ (seed >>> 16)) & 0xFFFFFFFF;
return (seed & 0xFFFFFFF) / 0x10000000;
};
}
You can use it like this:
const deterministicRandom = createDeterministicRandom()
deterministicRandom()
// => 0.9872818551957607
deterministicRandom()
// => 0.34880331158638
No, like they said it is not possible to seed Math.random()
but you can install external package which make provision for that. i used these package which can be install using these command
npm i random-seed
the example is gotten from the package documentation.
var seed = 'Hello World',
rand1 = require('random-seed').create(seed),
rand2 = require('random-seed').create(seed);
console.log(rand1(100), rand2(100));
follow the link for documentation https://www.npmjs.com/package/random-seed
SIN(id + seed) is a very interesting replacement for RANDOM functions that cannot be seeded like SQLite:
https://stackoverflow.com/a/75089040/7776828
Most of the answers here produce biased results. So here's a tested function based on seedrandom library from github:
!function(f,a,c){var s,l=256,p="random",d=c.pow(l,6),g=c.pow(2,52),y=2*g,h=l-1;function n(n,t,r){function e(){for(var n=u.g(6),t=d,r=0;n<g;)n=(n+r)*l,t*=l,r=u.g(1);for(;y<=n;)n/=2,t/=2,r>>>=1;return(n+r)/t}var o=[],i=j(function n(t,r){var e,o=[],i=typeof t;if(r&&"object"==i)for(e in t)try{o.push(n(t[e],r-1))}catch(n){}return o.length?o:"string"==i?t:t+"\0"}((t=1==t?{entropy:!0}:t||{}).entropy?[n,S(a)]:null==n?function(){try{var n;return s&&(n=s.randomBytes)?n=n(l):(n=new Uint8Array(l),(f.crypto||f.msCrypto).getRandomValues(n)),S(n)}catch(n){var t=f.navigator,r=t&&t.plugins;return[+new Date,f,r,f.screen,S(a)]}}():n,3),o),u=new m(o);return e.int32=function(){return 0|u.g(4)},e.quick=function(){return u.g(4)/4294967296},e.double=e,j(S(u.S),a),(t.pass||r||function(n,t,r,e){return e&&(e.S&&v(e,u),n.state=function(){return v(u,{})}),r?(c[p]=n,t):n})(e,i,"global"in t?t.global:this==c,t.state)}function m(n){var t,r=n.length,u=this,e=0,o=u.i=u.j=0,i=u.S=[];for(r||(n=[r++]);e<l;)i[e]=e++;for(e=0;e<l;e++)i[e]=i[o=h&o+n[e%r]+(t=i[e])],i[o]=t;(u.g=function(n){for(var t,r=0,e=u.i,o=u.j,i=u.S;n--;)t=i[e=h&e+1],r=r*l+i[h&(i[e]=i[o=h&o+t])+(i[o]=t)];return u.i=e,u.j=o,r})(l)}function v(n,t){return t.i=n.i,t.j=n.j,t.S=n.S.slice(),t}function j(n,t){for(var r,e=n+"",o=0;o<e.length;)t[h&o]=h&(r^=19*t[h&o])+e.charCodeAt(o++);return S(t)}function S(n){return String.fromCharCode.apply(0,n)}if(j(c.random(),a),"object"==typeof module&&module.exports){module.exports=n;try{s=require("crypto")}catch(n){}}else"function"==typeof define&&define.amd?define(function(){return n}):c["seed"+p]=n}("undefined"!=typeof self?self:this,[],Math);
function randIntWithSeed(seed, max=1) {
/* returns a random number between [0,max] including zero and max
seed can be either string or integer */
return Math.round(new Math.seedrandom('seed' + seed)()) * max
}
test for true randomness of this code: https://es6console.com/kkjkgur2/
There are plenty of good answers here but I had a similar issue with the additional requirement that I would like portability between Java's random number generator and whatever I ended up using in JavaScript.
I found the java-random package
These two pieces of code had identical output assuming the seed is the same:
Java:
Random randomGenerator = new Random(seed);
int randomInt;
for (int i=0; i<10; i++) {
randomInt = randomGenerator.nextInt(50);
System.out.println(randomInt);
}
JavaScript:
let Random = require('java-random');
let rng = new Random(seed);
for (let i=0; i<10; i++) {
let val = rng.nextInt(50);
console.log(val);
}
I have written a function that returns a seeded random number, it uses Math.sin to have a long random number and uses the seed to pick numbers from that.
Use :
seedRandom("k9]:2#", 15)
it will return your seeded number
the first parameter is any string value ; your seed.
the second parameter is how many digits will return.
function seedRandom(inputSeed, lengthOfNumber){
var output = "";
var seed = inputSeed.toString();
var newSeed = 0;
var characterArray = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','U','R','S','T','U','V','W','X','Y','Z','!','#','#','$','%','^','&','*','(',')',' ','[','{',']','}','|',';',':',"'",',','<','.','>','/','?','`','~','-','_','=','+'];
var longNum = "";
var counter = 0;
var accumulator = 0;
for(var i = 0; i < seed.length; i++){
var a = seed.length - (i+1);
for(var x = 0; x < characterArray.length; x++){
var tempX = x.toString();
var lastDigit = tempX.charAt(tempX.length-1);
var xOutput = parseInt(lastDigit);
addToSeed(characterArray[x], xOutput, a, i);
}
}
function addToSeed(character, value, a, i){
if(seed.charAt(i) === character){newSeed = newSeed + value * Math.pow(10, a)}
}
newSeed = newSeed.toString();
var copy = newSeed;
for(var i=0; i<lengthOfNumber*9; i++){
newSeed = newSeed + copy;
var x = Math.sin(20982+(i)) * 10000;
var y = Math.floor((x - Math.floor(x))*10);
longNum = longNum + y.toString()
}
for(var i=0; i<lengthOfNumber; i++){
output = output + longNum.charAt(accumulator);
counter++;
accumulator = accumulator + parseInt(newSeed.charAt(counter));
}
return(output)
}
A simple approach for a fixed seed:
function fixedrandom(p){
const seed = 43758.5453123;
return (Math.abs(Math.sin(p)) * seed)%1;
}
In PHP, there is function srand(seed) which generate fixed random value for particular seed.
But, in JS, there is no such inbuilt function.
However, we can write simple and short function.
Step 1: Choose some Seed (Fix Number).
var seed = 100;
Number should be Positive Integer and greater than 1, further explanation in Step 2.
Step 2: Perform Math.sin() function on Seed, it will give sin value of that number. Store this value in variable x.
var x;
x = Math.sin(seed); // Will Return Fractional Value between -1 & 1 (ex. 0.4059..)
sin() method returns a Fractional value between -1 and 1.And we don't need Negative value, therefore, in first step choose number greater than 1.
Step 3: Returned Value is a Fractional value between -1 and 1. So mulitply this value with 10 for making it more than 1.
x = x * 10; // 10 for Single Digit Number
Step 4: Multiply the value with 10 for additional digits
x = x * 10; // Will Give value between 10 and 99 OR
x = x * 100; // Will Give value between 100 and 999
Multiply as per requirement of digits.
The result will be in decimal.
Step 5: Remove value after Decimal Point by Math's Round (Math.round()) Method.
x = Math.round(x); // This will give Integer Value.
Step 6: Turn Negative Values into Positive (if any) by Math.abs method
x = Math.abs(x); // Convert Negative Values into Positive(if any)
Explanation End.Final Code
var seed = 111; // Any Number greater than 1
var digit = 10 // 1 => single digit, 10 => 2 Digits, 100 => 3 Digits and so. (Multiple of 10)
var x; // Initialize the Value to store the result
x = Math.sin(seed); // Perform Mathematical Sin Method on Seed.
x = x * 10; // Convert that number into integer
x = x * digit; // Number of Digits to be included
x = Math.round(x); // Remove Decimals
x = Math.abs(x); // Convert Negative Number into Positive
Clean and Optimized Functional Code
function random_seed(seed, digit = 1) {
var x = Math.abs(Math.round(Math.sin(seed++) * 10 * digit));
return x;
}
Then Call this function using
random_seed(any_number, number_of_digits)any_number is must and should be greater than 1.number_of_digits is optional parameter and if nothing passed, 1 Digit will return.
random_seed(555); // 1 Digit
random_seed(234, 1); // 1 Digit
random_seed(7895656, 1000); // 4 Digit
For a number between 0 and 100.
Number.parseInt(Math.floor(Math.random() * 100))
Let's say you have a function that takes both x and y, real numbers that are integers, as arguments.
What would you put inside that function, using only mathematical operators, so that no two given sequences of arguments could ever return the same value, be it any kind of value?
Example of a function that fails at doing this:
function myfunction(x,y){
return x * y;
}
// myfunction(2,6) and myfunction(3,4) will both return 12
// myfunction(2,6) and myfunction(6,2) also both return 12.
As already noted in comments, at the level of JavaScript numbers such a function can't exist, simply because assuming that we're working with integer-valued IEEE 754 binary64 floats there are more possible input pairs than possible output values.
But to the mathematical question of whether there is a simple, injective function from pairs of integers to a single integer, the answer is yes. Here's one such function that uses only addition and multiplication, so should fit the questioner's "using only mathematical operators" constraint.
First we map each of the inputs from the domain of integers to the domain of nonnegative integers. The polynomial map x ↦ 2*x*x + x will do that for us, and maps distinct values to distinct values. (Sketch of proof: if 2*x*x + x == 2*y*y + y for some integers x and y, then rearranging and factoring gives (x - y) * (2*x + 2*y + 1) == 0; the second factor can never be zero for integers x and y, so the first factor must be zero and x == y.)
Second, given a pair of nonnegative integers (a, b), we map that pair to a single (nonnegative) integer using (a, b) ↦ (a + b)*(a + b) + a. It's easy to see that this, too, is injective: given the value of (a + b)*(a + b) + a, I can recover the value of a + b by taking the integer square root, and from there recover a and b.
Here's some Python code demonstrating the above:
def encode_pair(x, y):
""" Encode a pair of integers as a single (nonnegative) integer. """
a = 2*x*x + x
b = 2*y*y + y
return (a + b)*(a + b) + a
We can easily check that there are no repetitions for small x and y: here we take all pairs (x, y) with -500 <= x < 500 and -500 <= y < 500, and find the set containing encode_pair(x, y) for each combination. If all goes well, we should end up with a set with exactly 1 million entries, one per input combination.
>>> all_outputs = {encode_pair(x, y) for x in range(-500, 500) for y in range(-500, 500)}
>>> len(all_outputs)
1000000
>>> min(all_outputs)
0
But perhaps a more convincing way to establish the injectivity is to give an explicit inverse, showing that the original (x, y) can be recovered from the output. Here's that inverse function. It makes use of Python's integer square root operation math.isqrt, which is available only for Python >= 3.8, but is easy to implement yourself if you need it.
from math import isqrt
def decode_pair(n):
""" Decode an integer produced by encode_pair. """
a_plus_b = isqrt(n)
a = n - a_plus_b*a_plus_b
b = a_plus_b - a
c = isqrt(8*a + 1)
d = isqrt(8*b + 1)
return ((2 - c%4) * c - 1) // 4, ((2 - d%4) * d - 1) // 4
Example usage:
>>> encode_pair(3, 7)
15897
>>> decode_pair(15897)
(3, 7)
Depending on what you allow as a "mathematical operator" (which isn't really a particularly well-defined term), there are tighter functions possible. Here's a variant of the above that provides not just an injection but a bijection: every integer appears as the encoding of some pair of integers. It extends the set of mathematical operators used to include subtraction, division and absolute value. (Note that all divisions appearing in encode_pair are exact integer divisions, without any remainder.)
def encode_pair(x, y):
""" Encode a pair of integers as a single integer.
This gives a bijective map Z x Z -> Z.
"""
ax = (abs(2 * x + 1) - 1) // 2 # x if x >= 0, -1-x if x < 0
sx = (ax - x) // (2 * ax + 1) # 0 if x >= 0, 1 if x < 0
ay = (abs(2 * y + 1) - 1) // 2 # y if y >= 0, -1-y if y < 0
sy = (ay - y) // (2 * ay + 1) # 0 if y >= 0, 1 if y < 0
xy = (ax + ay + 1) * (ax + ay) // 2 + ax # encode ax and ay as xy
an = 2 * xy + sx # encode xy and sx as an
n = an - (2 * an + 1) * sy # encode an and sy as n
return n
def decode_pair(n):
""" Inverse of encode_pair. """
# decode an and sy from n
an = (abs(2 * n + 1) - 1) // 2
sy = (an - n) // (2 * an + 1)
# decode xy and sx from an
sx = an % 2
xy = an // 2
# decode ax and ay from xy
ax_plus_ay = (isqrt(8 * xy + 1) - 1) // 2
ax = xy - ax_plus_ay * (ax_plus_ay + 1) // 2
ay = ax_plus_ay - ax
# recover x from ax and sx, and y from ay and sy
x = ax - (1 + 2 * ax) * sx
y = ay - (1 + 2 * ay) * sy
return x, y
And now every integer appears as the encoding of exactly one pair, so we can start with an arbitrary integer, decode it to a pair, and re-encode to recover the same integer:
>>> n = -12345
>>> decode_pair(n)
(67, -44)
>>> encode_pair(67, -44)
-12345
The encode_pair function above is deliberately quite verbose, in order to explain all the steps involved. But the code and the algebra can be simplified: here's exactly the same computation expressed more compactly.
def encode_pair_cryptic(x, y):
""" Encode a pair of integers as a single integer.
This gives a bijective map Z x Z -> Z.
"""
c = abs(2 * x + 1)
d = abs(2 * y + 1)
e = (2 * y + 1) * ((c + d)**2 * c + 2 * (c - d) * c - 4 * x - 2)
return (e - 2 * c * d) // (4 * c * d)
encode_pair_cryptic gives exactly the same results as encode_pair. I'll give one example, and leave the reader to figure out the equivalence.
>>> encode_pair(47, -53)
-9995
>>> encode_pair_cryptic(47, -53)
-9995
I'm no math wiz but found this question kinda fun so I gave it a shot. This is by no means scalable to large number since I'm using prime numbers as exponents and gets out of control really quick. But tested up to 90,000 combinations and found no duplicates.
The code below has a couple extra functions generateValues() and hasDuplicates() that is just there to run and test multiple values coming from the output of myFunction()
BigNumber.config({ EXPONENTIAL_AT: 10 })
// This function is just to generate the array of prime numbers
function getPrimeArray(num) {
const array = [];
let isPrime;
let i = 2;
while (array.length < num + 1) {
for (let j = 2; (isPrime = i === j || i % j !== 0) && j <= i / 2; j++) {}
isPrime && array.push(i);
i++;
}
return array;
}
function myFunction(a, b) {
const primes = getPrimeArray(Math.max(a, b));
// Using the prime array, primes[a]^primes[b]
return BigNumber(primes[a]).pow(primes[b]).toString();
}
function generateValues(upTo) {
const results = [];
for (let i = 1; i < upTo + 1; i++) {
for (let j = 1; j < upTo + 1; j++) {
console.log(`${i},${j}`)
results.push(myFunction(i,j));
}
}
return results.sort();
}
function hasDuplicates(arr) {
return new Set(arr).size !== arr.length;
}
const values = generateValues(50)
console.log(`Checked ${values.length} values; duplicates: ${hasDuplicates(values)}`)
<script src="https://cdnjs.cloudflare.com/ajax/libs/bignumber.js/8.0.2/bignumber.min.js"></script>
Explanation of what's going on:
Using the example of myFunction(1,3)
And the array of primes [2, 3, 5, 7]
This would take the 2nd and 4th items, 3 and 7 which would result in 3^7=2187
Using 300 as the max generated 90,000 combinations with no duplicates (However it took quite some time.) I tried using a max of 500 but the fan on my laptop sounded like a jet engine taking off so gave up on it.
If x and y are some fixed size integers (eg 8 bits) then what you want is possible if the return of f has at least as many bits as the sum of the number of bits of x an y (ie 16 in the example) and not otherwise.
In the 8 bit example f(x,y) = (x<<8)+y would do. This is because if g(z) = ((z>>8), z&255) then g(f(x,y)) = (x,y). The impossibility comes from the pigeon hole principle: if we want (in the example) to map the pairs (x,y) (of which there 2^16) 1-1 to some integer type, then we must have at least 2^16 values of this type.
function myfunction(x,y){
x = 1/x;
y = 1/y;
let yLength = ("" + y).length
for(let i = 0; i < yLength; i++){
x*=10;
}
return (x + y)
}
console.log(myfunction(2,12))
console.log(myfunction(21,2))
Based on your question and you comments, I understood the following:
You want to pass 2 real numbers into a function. The function should use mathematical operators to generate a new result.
Your question is, if there is any kind of mathematical equation/function you could use, that would ALWAYS deliver a unique result.
If that's so, then the answer is no. You can make your function as complicated as possible and get a result(c) using the two numbers (a & b).
In this case I would look for another combination which could give me the result(c) using the same equation/function. Therefore I would use the system of linear equation to solve this mathematical issue.
In general, a system with fewer equations than unknowns has infinitely many solutions, but it may have no solution. Such a system is known as an underdetermined system.
In our case we would have one equation which gives us one result and two unknowns, therefore it would have infinitely many solutions because we already have a solution, so there is no way for the system to have no solutions at all.
More about this topic.
Edit:
I just recognized that some of us understood the domain of the function in a different way. I was thinking about real numbers (R) but it seems many assumed you talk about integers (Z) only.
Well I guess
real integers
wasnt clear enough, at least for me.
So if we would use integers only, I have no idea if that is possible to always have different results. Some users suggested a topic about that here I am also interested to take a look into that too.
I am searching for a way to calculate the Cumulative distribution function in Javascript. Are there classes which have implemented this? Do you have an idea to get this to work? It does not need to be 100% percent accurate but I need a good idea of the value.
http://en.wikipedia.org/wiki/Cumulative_distribution_function
I was able to write my own function with the help of Is there an easily available implementation of erf() for Python? and the knowledge from wikipedia.
The calculation is not 100% correct as it is just a approximation.
function normalcdf(mean, sigma, to)
{
var z = (to-mean)/Math.sqrt(2*sigma*sigma);
var t = 1/(1+0.3275911*Math.abs(z));
var a1 = 0.254829592;
var a2 = -0.284496736;
var a3 = 1.421413741;
var a4 = -1.453152027;
var a5 = 1.061405429;
var erf = 1-(((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*Math.exp(-z*z);
var sign = 1;
if(z < 0)
{
sign = -1;
}
return (1/2)*(1+sign*erf);
}
normalcdf(30, 25, 1.4241); //-> 0.12651187738346226
//wolframalpha.com 0.12651200000000000
The math.js library provides an erf function. Based on a definition found at Wolfram Alpha , the cdfNormalfunction can be implemented like this in Javascript:
const mathjs = require('mathjs')
function cdfNormal (x, mean, standardDeviation) {
return (1 - mathjs.erf((mean - x ) / (Math.sqrt(2) * standardDeviation))) / 2
}
In the node.js console:
> console.log(cdfNormal(5, 30, 25))
> 0.15865525393145707 // Equal to Wolfram Alpha's result at: https://sandbox.open.wolframcloud.com/app/objects/4935c1cb-c245-4d8d-9668-4d353ad714ec#sidebar=compute
This formula will give the correct normal CDF unlike the currently accepted answer
function ncdf(x, mean, std) {
var x = (x - mean) / std
var t = 1 / (1 + .2315419 * Math.abs(x))
var d =.3989423 * Math.exp( -x * x / 2)
var prob = d * t * (.3193815 + t * ( -.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))))
if( x > 0 ) prob = 1 - prob
return prob
}
This answer comes from math.ucla.edu
Due to some needs in the past, i put together an implementation of distribution function in javascript. my library is available at github. You can take a look at https://github.com/chen0040/js-stats
it provides javascript implementation of CDF and inverse CDF for Normal distribution, Student's T distribution, F distribution and Chi-Square Distribution
To use the js lib for obtaining CDF and inverse CDF:
jsstats = require('js-stats');
//====================NORMAL DISTRIBUTION====================//
var mu = 0.0; // mean
var sd = 1.0; // standard deviation
var normal_distribution = new jsstats.NormalDistribution(mu, sd);
var X = 10.0; // point estimate value
var p = normal_distribution.cumulativeProbability(X); // cumulative probability
var p = 0.7; // cumulative probability
var X = normal_distribution.invCumulativeProbability(p); // point estimate value
//====================T DISTRIBUTION====================//
var df = 10; // degrees of freedom for t-distribution
var t_distribution = new jsstats.TDistribution(df);
var t_df = 10.0; // point estimate or test statistic
var p = t_distribution.cumulativeProbability(t_df); // cumulative probability
var p = 0.7;
var t_df = t_distribution.invCumulativeProbability(p); // point estimate or test statistic
//====================F DISTRIBUTION====================//
var df1 = 10; // degrees of freedom for f-distribution
var df2 = 20; // degrees of freedom for f-distribution
var f_distribution = new jsstats.FDistribution(df1, df2);
var F = 10.0; // point estimate or test statistic
var p = f_distribution.cumulativeProbability(F); // cumulative probability
//====================Chi Square DISTRIBUTION====================//
var df = 10; // degrees of freedom for cs-distribution
var cs_distribution = new jsstats.ChiSquareDistribution(df);
var X = 10.0; // point estimate or test statistic
var p = cs_distribution.cumulativeProbability(X); // cumulative probability
This is a brute force implementation, but accurate to more digits of precision. The approximation above is accurate within 10^-7. My implementation runs slower (700 nano-sec) but is accurate within 10^-14. normal(25,30,1.4241) === 0.00022322110257305683, vs wolfram's 0.000223221102572082.
It takes the power series of the standard normal pdf, i.e. the bell-curve, and then integrates the series.
I originally wrote this in C, so I concede some of the optimizations might seem silly in Javascript.
function normal(x, mu, sigma) {
return stdNormal((x-mu)/sigma);
}
function stdNormal(z) {
var j, k, kMax, m, values, total, subtotal, item, z2, z4, a, b;
// Power series is not stable at these extreme tail scenarios
if (z < -6) { return 0; }
if (z > 6) { return 1; }
m = 1; // m(k) == (2**k)/factorial(k)
b = z; // b(k) == z ** (2*k + 1)
z2 = z * z; // cache of z squared
z4 = z2 * z2; // cache of z to the 4th
values = [];
// Compute the power series in groups of two terms.
// This reduces floating point errors because the series
// alternates between positive and negative.
for (k=0; k<100; k+=2) {
a = 2*k + 1;
item = b / (a*m);
item *= (1 - (a*z2)/((a+1)*(a+2)));
values.push(item);
m *= (4*(k+1)*(k+2));
b *= z4;
}
// Add the smallest terms to the total first that
// way we minimize the floating point errors.
total = 0;
for (k=49; k>=0; k--) {
total += values[k];
}
// Multiply total by 1/sqrt(2*PI)
// Then add 0.5 so that stdNormal(0) === 0.5
return 0.5 + 0.3989422804014327 * total;
}
You can also take a look here, it's a scientific calculator implemented in javascript, it includes erf and its author claims no copyright on the implementation.