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;








1















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?










share|improve this question






















  • 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











  • 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











  • 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


















1















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?










share|improve this question






















  • 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











  • 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











  • 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














1












1








1








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?










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Mar 22 at 10:02









cubecube

2,76862445




2,76862445












  • 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











  • 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











  • 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


















  • 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











  • 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











  • 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

















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













1 Answer
1






active

oldest

votes


















1














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.






share|improve this answer

























  • 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












  • Wow. Works perfectly, Now I just need to wrap my head around it :-)

    – cube
    Mar 27 at 14:50











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
);



);













draft saved

draft discarded


















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









1














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.






share|improve this answer

























  • 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












  • Wow. Works perfectly, Now I just need to wrap my head around it :-)

    – cube
    Mar 27 at 14:50















1














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.






share|improve this answer

























  • 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












  • Wow. Works perfectly, Now I just need to wrap my head around it :-)

    – cube
    Mar 27 at 14:50













1












1








1







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.






share|improve this answer















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.







share|improve this answer














share|improve this answer



share|improve this answer








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 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

















  • 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












  • 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



















draft saved

draft discarded
















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript