Mixing function for non power of 2 integer intervals Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 23, 2019 at 00:00UTC (8:00pm US/Eastern) Data science time! April 2019 and salary with experience The Ask Question Wizard is Live!How to generate a predictable shuffling of a sequence without generating the whole sequence in advance?How do I make a permutation function that accepts one value at a time?Fastest way to determine if an integer's square root is an integerWhat is JavaScript's highest integer value that a number can go to without losing precision?How to check if a number is a power of 2Designing function f(f(n)) == -nInteger division with remainder in JavaScript?hashing a small number to a random looking 64 bit integerHow do I make a deterministic pseudo-random permutation generator function?How do I make a permutation function that accepts one value at a time?hashing algorithms for stringsHash function for clustered integers
Find 108 by using 3,4,6
Why wasn't DOSKEY integrated with COMMAND.COM?
What is the difference between globalisation and imperialism?
How often does castling occur in grandmaster games?
How does Python know the values already stored in its memory?
Denied boarding although I have proper visa and documentation. To whom should I make a complaint?
ArcGIS Pro Python arcpy.CreatePersonalGDB_management
Can a new player join a group only when a new campaign starts?
Is CEO the "profession" with the most psychopaths?
When a candle burns, why does the top of wick glow if bottom of flame is hottest?
How to install press fit bottom bracket into new frame
Is there any word for a place full of confusion?
How could we fake a moon landing now?
How does the math work when buying airline miles?
Central Vacuuming: Is it worth it, and how does it compare to normal vacuuming?
Why do we need to use the builder design pattern when we can do the same thing with setters?
Crossing US/Canada Border for less than 24 hours
Converted a Scalar function to a TVF function for parallel execution-Still running in Serial mode
Is grep documentation about ignoring case wrong, since it doesn't ignore case in filenames?
Why is it faster to reheat something than it is to cook it?
What initially awakened the Balrog?
What are the diatonic extended chords of C major?
What is a fractional matching?
What do you call the main part of a joke?
Mixing function for non power of 2 integer intervals
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 23, 2019 at 00:00UTC (8:00pm US/Eastern)
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!How to generate a predictable shuffling of a sequence without generating the whole sequence in advance?How do I make a permutation function that accepts one value at a time?Fastest way to determine if an integer's square root is an integerWhat is JavaScript's highest integer value that a number can go to without losing precision?How to check if a number is a power of 2Designing function f(f(n)) == -nInteger division with remainder in JavaScript?hashing a small number to a random looking 64 bit integerHow do I make a deterministic pseudo-random permutation generator function?How do I make a permutation function that accepts one value at a time?hashing algorithms for stringsHash function for clustered integers
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I'm looking for a mixing function that given an integer from an interval <0, n) returns a random-looking integer from the same interval. The interval size n will typically be a composite non power of 2 number. I need the function to be one to one. It can only use O(1) memory, O(1) time is strongly preferred. I'm not too concerned about randomness of the output, but visually it should look random enough (see next paragraph).
I want to use this function as a pixel shuffling step in a realtime-ish renderer to select the order in which pixels are rendered (The output will be displayed after a fixed time and if it's not done yet this gives me a noisy but fast partial preview). Interval size n will be the number of pixels in the render (n = 1920*1080 = 2073600 would be a typical value). The function must be one to one so that I can be sure that every pixel is rendered exactly once when finished.
I've looked at the reversible building blocks used by hash prospector, but these are mostly specific to power of 2 ranges.
The only other method I could think of is multiply by large prime, but it doesn't give particularly nice random looking outputs.
What are some other options here?
math hash unsigned-integer
|
show 5 more comments
I'm looking for a mixing function that given an integer from an interval <0, n) returns a random-looking integer from the same interval. The interval size n will typically be a composite non power of 2 number. I need the function to be one to one. It can only use O(1) memory, O(1) time is strongly preferred. I'm not too concerned about randomness of the output, but visually it should look random enough (see next paragraph).
I want to use this function as a pixel shuffling step in a realtime-ish renderer to select the order in which pixels are rendered (The output will be displayed after a fixed time and if it's not done yet this gives me a noisy but fast partial preview). Interval size n will be the number of pixels in the render (n = 1920*1080 = 2073600 would be a typical value). The function must be one to one so that I can be sure that every pixel is rendered exactly once when finished.
I've looked at the reversible building blocks used by hash prospector, but these are mostly specific to power of 2 ranges.
The only other method I could think of is multiply by large prime, but it doesn't give particularly nice random looking outputs.
What are some other options here?
math hash unsigned-integer
f(x) = (p*x+b) (mod n)
wherep
is a large prime withgcd(p,n) = 1
? Theb
will make it seem more random.
– John Coleman
Mar 22 at 13:29
I've tried it and it doesn't help much :/
– cube
Mar 22 at 13:36
How about using a generator which has a power of 2, using the smallest power of 2 which is> n
? Throw away generated indices which exceedn
. On average, you will throw away less than 1 out of every 2 outputs. If the generator is fast, it will still be fast if used this way.
– John Coleman
Mar 22 at 13:39
Would that mapping remain one to one?
– cube
Mar 26 at 13:11
Yes: For example, given a permutation0, 4, 7, 1, 5, 3, 2, 6
of0-7
, if you throw away values which exceed 5 you get a permutation0, 4, 1, 5, 3, 2
of0-5
. Think of this as a filter. A quasi-random way of going through 0-7 yields a quasi-random way for going through 0-5. There is some inefficiency going this route, but if the generator with a cycle which is a power of 2 is both fast and has a good distribution, then the performance should be acceptable.
– John Coleman
Mar 26 at 14:08
|
show 5 more comments
I'm looking for a mixing function that given an integer from an interval <0, n) returns a random-looking integer from the same interval. The interval size n will typically be a composite non power of 2 number. I need the function to be one to one. It can only use O(1) memory, O(1) time is strongly preferred. I'm not too concerned about randomness of the output, but visually it should look random enough (see next paragraph).
I want to use this function as a pixel shuffling step in a realtime-ish renderer to select the order in which pixels are rendered (The output will be displayed after a fixed time and if it's not done yet this gives me a noisy but fast partial preview). Interval size n will be the number of pixels in the render (n = 1920*1080 = 2073600 would be a typical value). The function must be one to one so that I can be sure that every pixel is rendered exactly once when finished.
I've looked at the reversible building blocks used by hash prospector, but these are mostly specific to power of 2 ranges.
The only other method I could think of is multiply by large prime, but it doesn't give particularly nice random looking outputs.
What are some other options here?
math hash unsigned-integer
I'm looking for a mixing function that given an integer from an interval <0, n) returns a random-looking integer from the same interval. The interval size n will typically be a composite non power of 2 number. I need the function to be one to one. It can only use O(1) memory, O(1) time is strongly preferred. I'm not too concerned about randomness of the output, but visually it should look random enough (see next paragraph).
I want to use this function as a pixel shuffling step in a realtime-ish renderer to select the order in which pixels are rendered (The output will be displayed after a fixed time and if it's not done yet this gives me a noisy but fast partial preview). Interval size n will be the number of pixels in the render (n = 1920*1080 = 2073600 would be a typical value). The function must be one to one so that I can be sure that every pixel is rendered exactly once when finished.
I've looked at the reversible building blocks used by hash prospector, but these are mostly specific to power of 2 ranges.
The only other method I could think of is multiply by large prime, but it doesn't give particularly nice random looking outputs.
What are some other options here?
math hash unsigned-integer
math hash unsigned-integer
asked Mar 22 at 10:02
cubecube
2,76862445
2,76862445
f(x) = (p*x+b) (mod n)
wherep
is a large prime withgcd(p,n) = 1
? Theb
will make it seem more random.
– John Coleman
Mar 22 at 13:29
I've tried it and it doesn't help much :/
– cube
Mar 22 at 13:36
How about using a generator which has a power of 2, using the smallest power of 2 which is> n
? Throw away generated indices which exceedn
. On average, you will throw away less than 1 out of every 2 outputs. If the generator is fast, it will still be fast if used this way.
– John Coleman
Mar 22 at 13:39
Would that mapping remain one to one?
– cube
Mar 26 at 13:11
Yes: For example, given a permutation0, 4, 7, 1, 5, 3, 2, 6
of0-7
, if you throw away values which exceed 5 you get a permutation0, 4, 1, 5, 3, 2
of0-5
. Think of this as a filter. A quasi-random way of going through 0-7 yields a quasi-random way for going through 0-5. There is some inefficiency going this route, but if the generator with a cycle which is a power of 2 is both fast and has a good distribution, then the performance should be acceptable.
– John Coleman
Mar 26 at 14:08
|
show 5 more comments
f(x) = (p*x+b) (mod n)
wherep
is a large prime withgcd(p,n) = 1
? Theb
will make it seem more random.
– John Coleman
Mar 22 at 13:29
I've tried it and it doesn't help much :/
– cube
Mar 22 at 13:36
How about using a generator which has a power of 2, using the smallest power of 2 which is> n
? Throw away generated indices which exceedn
. On average, you will throw away less than 1 out of every 2 outputs. If the generator is fast, it will still be fast if used this way.
– John Coleman
Mar 22 at 13:39
Would that mapping remain one to one?
– cube
Mar 26 at 13:11
Yes: For example, given a permutation0, 4, 7, 1, 5, 3, 2, 6
of0-7
, if you throw away values which exceed 5 you get a permutation0, 4, 1, 5, 3, 2
of0-5
. Think of this as a filter. A quasi-random way of going through 0-7 yields a quasi-random way for going through 0-5. There is some inefficiency going this route, but if the generator with a cycle which is a power of 2 is both fast and has a good distribution, then the performance should be acceptable.
– John Coleman
Mar 26 at 14:08
f(x) = (p*x+b) (mod n)
where p
is a large prime with gcd(p,n) = 1
? The b
will make it seem more random.– John Coleman
Mar 22 at 13:29
f(x) = (p*x+b) (mod n)
where p
is a large prime with gcd(p,n) = 1
? The b
will make it seem more random.– John Coleman
Mar 22 at 13:29
I've tried it and it doesn't help much :/
– cube
Mar 22 at 13:36
I've tried it and it doesn't help much :/
– cube
Mar 22 at 13:36
How about using a generator which has a power of 2, using the smallest power of 2 which is
> n
? Throw away generated indices which exceed n
. On average, you will throw away less than 1 out of every 2 outputs. If the generator is fast, it will still be fast if used this way.– John Coleman
Mar 22 at 13:39
How about using a generator which has a power of 2, using the smallest power of 2 which is
> n
? Throw away generated indices which exceed n
. On average, you will throw away less than 1 out of every 2 outputs. If the generator is fast, it will still be fast if used this way.– John Coleman
Mar 22 at 13:39
Would that mapping remain one to one?
– cube
Mar 26 at 13:11
Would that mapping remain one to one?
– cube
Mar 26 at 13:11
Yes: For example, given a permutation
0, 4, 7, 1, 5, 3, 2, 6
of 0-7
, if you throw away values which exceed 5 you get a permutation 0, 4, 1, 5, 3, 2
of 0-5
. Think of this as a filter. A quasi-random way of going through 0-7 yields a quasi-random way for going through 0-5. There is some inefficiency going this route, but if the generator with a cycle which is a power of 2 is both fast and has a good distribution, then the performance should be acceptable.– John Coleman
Mar 26 at 14:08
Yes: For example, given a permutation
0, 4, 7, 1, 5, 3, 2, 6
of 0-7
, if you throw away values which exceed 5 you get a permutation 0, 4, 1, 5, 3, 2
of 0-5
. Think of this as a filter. A quasi-random way of going through 0-7 yields a quasi-random way for going through 0-5. There is some inefficiency going this route, but if the generator with a cycle which is a power of 2 is both fast and has a good distribution, then the performance should be acceptable.– John Coleman
Mar 26 at 14:08
|
show 5 more comments
1 Answer
1
active
oldest
votes
Here is one solution based on the idea of primitive roots modulo a prime:
If a
is a primitive root mod p
then the function g(i) = a^i % p
is a permutation of the nonzero elements which are less than p
. This corresponds to the Lehmer prng. If n < p
, you can get a permutation of 0, ..., n-1
as follows: Given i
in that range, first add 1, then repeatedly multiply by a
, taking the result mod p
, until you get an element which is <= n
, at which point you return the result - 1.
To fill in the details, this paper contains a table which gives a series of primes (all of which are close to various powers of 2
) and corresponding primitive roots which are chosen so that they yield a generator with good statistical properties. Here is a part of that table, encoded as a Python dictionary in which the keys are the primes and the primitive roots are the values:
d = 32749: 30805,
65521: 32236,
131071: 66284,
262139: 166972,
524287: 358899,
1048573: 444362,
2097143: 1372180,
4194301: 1406151,
8388593: 5169235,
16777213: 9726917,
33554393: 32544832,
67108859: 11526618,
134217689: 70391260,
268435399: 150873839,
536870909: 219118189,
1073741789: 599290962
Given n
(in a certain range -- see the paper if you need to expand that range), you can find the smallest p
which works:
def find_p_a(n):
for p in sorted(d.keys()):
if n < p:
return p, d[p]
once you know n
and the matching p,a
the following function is a permutation of 0 ... n-1
:
def f(i,n,p,a):
x = a*(i+1) % p
while x > n:
x = a*x % p
return x-1
For a quick test:
n = 2073600
p,a = find_p_a(n) # p = 2097143, a = 1372180
nums = [f(i,n,p,a) for i in range(n)]
print(len(set(nums)) == n) #prints True
The average number of multiplications in f()
is p/n
, which in this case is 1.011
and will never be more than 2
(or very slightly larger since the p
are not exact powers of 2
). In practice this method is not fundamentally different from your "multiply by a large prime" approach, but in this case the factor is chosen more carefully, and the fact that sometimes more than 1 multiplication is required adding to the apparent randomness.
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
There is no error inf()
. Exponentiation is just repeated multiplication. The idea is thati+1
is equal toa^k % p
for somek
-- but you really don't need to know what thatk
is.a*(i+1) % k
will be the same asa^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.
– John Coleman
Mar 27 at 14:42
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55297154%2fmixing-function-for-non-power-of-2-integer-intervals%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Here is one solution based on the idea of primitive roots modulo a prime:
If a
is a primitive root mod p
then the function g(i) = a^i % p
is a permutation of the nonzero elements which are less than p
. This corresponds to the Lehmer prng. If n < p
, you can get a permutation of 0, ..., n-1
as follows: Given i
in that range, first add 1, then repeatedly multiply by a
, taking the result mod p
, until you get an element which is <= n
, at which point you return the result - 1.
To fill in the details, this paper contains a table which gives a series of primes (all of which are close to various powers of 2
) and corresponding primitive roots which are chosen so that they yield a generator with good statistical properties. Here is a part of that table, encoded as a Python dictionary in which the keys are the primes and the primitive roots are the values:
d = 32749: 30805,
65521: 32236,
131071: 66284,
262139: 166972,
524287: 358899,
1048573: 444362,
2097143: 1372180,
4194301: 1406151,
8388593: 5169235,
16777213: 9726917,
33554393: 32544832,
67108859: 11526618,
134217689: 70391260,
268435399: 150873839,
536870909: 219118189,
1073741789: 599290962
Given n
(in a certain range -- see the paper if you need to expand that range), you can find the smallest p
which works:
def find_p_a(n):
for p in sorted(d.keys()):
if n < p:
return p, d[p]
once you know n
and the matching p,a
the following function is a permutation of 0 ... n-1
:
def f(i,n,p,a):
x = a*(i+1) % p
while x > n:
x = a*x % p
return x-1
For a quick test:
n = 2073600
p,a = find_p_a(n) # p = 2097143, a = 1372180
nums = [f(i,n,p,a) for i in range(n)]
print(len(set(nums)) == n) #prints True
The average number of multiplications in f()
is p/n
, which in this case is 1.011
and will never be more than 2
(or very slightly larger since the p
are not exact powers of 2
). In practice this method is not fundamentally different from your "multiply by a large prime" approach, but in this case the factor is chosen more carefully, and the fact that sometimes more than 1 multiplication is required adding to the apparent randomness.
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
There is no error inf()
. Exponentiation is just repeated multiplication. The idea is thati+1
is equal toa^k % p
for somek
-- but you really don't need to know what thatk
is.a*(i+1) % k
will be the same asa^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.
– John Coleman
Mar 27 at 14:42
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
add a comment |
Here is one solution based on the idea of primitive roots modulo a prime:
If a
is a primitive root mod p
then the function g(i) = a^i % p
is a permutation of the nonzero elements which are less than p
. This corresponds to the Lehmer prng. If n < p
, you can get a permutation of 0, ..., n-1
as follows: Given i
in that range, first add 1, then repeatedly multiply by a
, taking the result mod p
, until you get an element which is <= n
, at which point you return the result - 1.
To fill in the details, this paper contains a table which gives a series of primes (all of which are close to various powers of 2
) and corresponding primitive roots which are chosen so that they yield a generator with good statistical properties. Here is a part of that table, encoded as a Python dictionary in which the keys are the primes and the primitive roots are the values:
d = 32749: 30805,
65521: 32236,
131071: 66284,
262139: 166972,
524287: 358899,
1048573: 444362,
2097143: 1372180,
4194301: 1406151,
8388593: 5169235,
16777213: 9726917,
33554393: 32544832,
67108859: 11526618,
134217689: 70391260,
268435399: 150873839,
536870909: 219118189,
1073741789: 599290962
Given n
(in a certain range -- see the paper if you need to expand that range), you can find the smallest p
which works:
def find_p_a(n):
for p in sorted(d.keys()):
if n < p:
return p, d[p]
once you know n
and the matching p,a
the following function is a permutation of 0 ... n-1
:
def f(i,n,p,a):
x = a*(i+1) % p
while x > n:
x = a*x % p
return x-1
For a quick test:
n = 2073600
p,a = find_p_a(n) # p = 2097143, a = 1372180
nums = [f(i,n,p,a) for i in range(n)]
print(len(set(nums)) == n) #prints True
The average number of multiplications in f()
is p/n
, which in this case is 1.011
and will never be more than 2
(or very slightly larger since the p
are not exact powers of 2
). In practice this method is not fundamentally different from your "multiply by a large prime" approach, but in this case the factor is chosen more carefully, and the fact that sometimes more than 1 multiplication is required adding to the apparent randomness.
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
There is no error inf()
. Exponentiation is just repeated multiplication. The idea is thati+1
is equal toa^k % p
for somek
-- but you really don't need to know what thatk
is.a*(i+1) % k
will be the same asa^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.
– John Coleman
Mar 27 at 14:42
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
add a comment |
Here is one solution based on the idea of primitive roots modulo a prime:
If a
is a primitive root mod p
then the function g(i) = a^i % p
is a permutation of the nonzero elements which are less than p
. This corresponds to the Lehmer prng. If n < p
, you can get a permutation of 0, ..., n-1
as follows: Given i
in that range, first add 1, then repeatedly multiply by a
, taking the result mod p
, until you get an element which is <= n
, at which point you return the result - 1.
To fill in the details, this paper contains a table which gives a series of primes (all of which are close to various powers of 2
) and corresponding primitive roots which are chosen so that they yield a generator with good statistical properties. Here is a part of that table, encoded as a Python dictionary in which the keys are the primes and the primitive roots are the values:
d = 32749: 30805,
65521: 32236,
131071: 66284,
262139: 166972,
524287: 358899,
1048573: 444362,
2097143: 1372180,
4194301: 1406151,
8388593: 5169235,
16777213: 9726917,
33554393: 32544832,
67108859: 11526618,
134217689: 70391260,
268435399: 150873839,
536870909: 219118189,
1073741789: 599290962
Given n
(in a certain range -- see the paper if you need to expand that range), you can find the smallest p
which works:
def find_p_a(n):
for p in sorted(d.keys()):
if n < p:
return p, d[p]
once you know n
and the matching p,a
the following function is a permutation of 0 ... n-1
:
def f(i,n,p,a):
x = a*(i+1) % p
while x > n:
x = a*x % p
return x-1
For a quick test:
n = 2073600
p,a = find_p_a(n) # p = 2097143, a = 1372180
nums = [f(i,n,p,a) for i in range(n)]
print(len(set(nums)) == n) #prints True
The average number of multiplications in f()
is p/n
, which in this case is 1.011
and will never be more than 2
(or very slightly larger since the p
are not exact powers of 2
). In practice this method is not fundamentally different from your "multiply by a large prime" approach, but in this case the factor is chosen more carefully, and the fact that sometimes more than 1 multiplication is required adding to the apparent randomness.
Here is one solution based on the idea of primitive roots modulo a prime:
If a
is a primitive root mod p
then the function g(i) = a^i % p
is a permutation of the nonzero elements which are less than p
. This corresponds to the Lehmer prng. If n < p
, you can get a permutation of 0, ..., n-1
as follows: Given i
in that range, first add 1, then repeatedly multiply by a
, taking the result mod p
, until you get an element which is <= n
, at which point you return the result - 1.
To fill in the details, this paper contains a table which gives a series of primes (all of which are close to various powers of 2
) and corresponding primitive roots which are chosen so that they yield a generator with good statistical properties. Here is a part of that table, encoded as a Python dictionary in which the keys are the primes and the primitive roots are the values:
d = 32749: 30805,
65521: 32236,
131071: 66284,
262139: 166972,
524287: 358899,
1048573: 444362,
2097143: 1372180,
4194301: 1406151,
8388593: 5169235,
16777213: 9726917,
33554393: 32544832,
67108859: 11526618,
134217689: 70391260,
268435399: 150873839,
536870909: 219118189,
1073741789: 599290962
Given n
(in a certain range -- see the paper if you need to expand that range), you can find the smallest p
which works:
def find_p_a(n):
for p in sorted(d.keys()):
if n < p:
return p, d[p]
once you know n
and the matching p,a
the following function is a permutation of 0 ... n-1
:
def f(i,n,p,a):
x = a*(i+1) % p
while x > n:
x = a*x % p
return x-1
For a quick test:
n = 2073600
p,a = find_p_a(n) # p = 2097143, a = 1372180
nums = [f(i,n,p,a) for i in range(n)]
print(len(set(nums)) == n) #prints True
The average number of multiplications in f()
is p/n
, which in this case is 1.011
and will never be more than 2
(or very slightly larger since the p
are not exact powers of 2
). In practice this method is not fundamentally different from your "multiply by a large prime" approach, but in this case the factor is chosen more carefully, and the fact that sometimes more than 1 multiplication is required adding to the apparent randomness.
edited Mar 27 at 14:24
answered Mar 27 at 14:16
John ColemanJohn Coleman
36k53478
36k53478
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
There is no error inf()
. Exponentiation is just repeated multiplication. The idea is thati+1
is equal toa^k % p
for somek
-- but you really don't need to know what thatk
is.a*(i+1) % k
will be the same asa^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.
– John Coleman
Mar 27 at 14:42
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
add a comment |
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
There is no error inf()
. Exponentiation is just repeated multiplication. The idea is thati+1
is equal toa^k % p
for somek
-- but you really don't need to know what thatk
is.a*(i+1) % k
will be the same asa^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.
– John Coleman
Mar 27 at 14:42
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
Thank you for the answer, looks promissing. Isn't there an error in the definition of f? You are multiplying a by something, but probably should be doing an exponentiation.
– cube
Mar 27 at 14:33
There is no error in
f()
. Exponentiation is just repeated multiplication. The idea is that i+1
is equal to a^k % p
for some k
-- but you really don't need to know what that k
is. a*(i+1) % k
will be the same as a^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.– John Coleman
Mar 27 at 14:42
There is no error in
f()
. Exponentiation is just repeated multiplication. The idea is that i+1
is equal to a^k % p
for some k
-- but you really don't need to know what that k
is. a*(i+1) % k
will be the same as a^(k+1) % p
. Doing it this way is the key to doing it in a way where each computation can be done in parallel.– John Coleman
Mar 27 at 14:42
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
Wow. Works perfectly, Now I just need to wrap my head around it :-)
– cube
Mar 27 at 14:50
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55297154%2fmixing-function-for-non-power-of-2-integer-intervals%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
f(x) = (p*x+b) (mod n)
wherep
is a large prime withgcd(p,n) = 1
? Theb
will make it seem more random.– John Coleman
Mar 22 at 13:29
I've tried it and it doesn't help much :/
– cube
Mar 22 at 13:36
How about using a generator which has a power of 2, using the smallest power of 2 which is
> n
? Throw away generated indices which exceedn
. On average, you will throw away less than 1 out of every 2 outputs. If the generator is fast, it will still be fast if used this way.– John Coleman
Mar 22 at 13:39
Would that mapping remain one to one?
– cube
Mar 26 at 13:11
Yes: For example, given a permutation
0, 4, 7, 1, 5, 3, 2, 6
of0-7
, if you throw away values which exceed 5 you get a permutation0, 4, 1, 5, 3, 2
of0-5
. Think of this as a filter. A quasi-random way of going through 0-7 yields a quasi-random way for going through 0-5. There is some inefficiency going this route, but if the generator with a cycle which is a power of 2 is both fast and has a good distribution, then the performance should be acceptable.– John Coleman
Mar 26 at 14:08