loop always returns same random integer [duplicate] - go

This question already has answers here:
Generating identical random numbers in sequence after time seed? (Running on my machine)
(2 answers)
Closed 2 years ago.
I've built a function that should return a random key from a array. When it runs it is always returning the same value.
for i := 0; i < 10; i++ {
rand.Seed(time.Now().Unix())
keyArray := [10]string{"key0", "key1", "key2", "key3", "key4", "key5", "key6", "key7", "key8", "key9"}
// fmt.Println(keyArray)
fmt.Println(keyArray[rand.Intn(len(keyArray))])
// var key = null
}
How can i fix this issue?

Don't seed the random number generator inside the loop. Seeding should be done only once. It sets the random number generator into a defined state depending on the seed value. Since the time does not change so fast you will get the same random number almost every time.

Related

Generating several random numbers in one transaction (Solidity)

Is there a way to generate several random numbers in a single transaction? Let's suppose I have this code:
function example(uint _prop) public{
while(random(100) < _prob){
// Do something
}
}
The condition of the while loop depends on the random number chosen in each iteration. Is it possible to do this with VRF (Chainlink)? Or can only one random number be generated for each transaction?
For now I'm using this solution:
function random(uint _interval) internal returns (uint) {
nonce++;
return uint(keccak256(abi.encodePacked(block.difficulty, block.timestamp, nonce))) % _interval;
}
but I know this is not a random number... This serves my purpose, but it is not formal. I want to improve it.
What you'd want to do, is make a Chainlink Random number request and then use than number to "expand" to more random numbers, like so:
function expand(uint256 randomValue, uint256 n) public pure returns (uint256[] memory expandedValues) {
expandedValues = new uint256[](n);
for (uint256 i = 0; i < n; i++) {
expandedValues[i] = uint256(keccak256(abi.encode(randomValue, i)));
}
return expandedValues;
}
Since we get the random number from a verifiably random location, we can then drop the number in this and get any number of random numbers after.

Is it safe to remove dictionary keys while iterating over it? [duplicate]

This question already has answers here:
Is it safe to remove selected keys from map within a range loop?
(4 answers)
Closed 3 years ago.
I wrote some code which does this, and it is working fine, but when reviewing the code I realize what I did might not have worked in other languages.
To give a contrived example:
dict := map[string]string{ "a": "1", "b": "2" }
for key, val := range dict {
fmt.Println(val)
delete(dict, "b")
}
This prints "1" and "2", and when I inspect dict afterward it is { "a": "1" } only.
So, I get the impression that it is safe to do this, but I'm wondering why?
Does range dict create a copy internally?
As always, the spec is the definitive answer. Under "For statements with range clause", item 3 (emphasis mine):
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.

Why does golang implement different behavior on `[]`operator between slice and map? [duplicate]

This question already has answers here:
Why are map values not addressable?
(2 answers)
Closed 4 years ago.
type S struct {
e int
}
func main() {
a := []S{{1}}
a[0].e = 2
b := map[int]S{0: {1}}
b[0].e = 2 // error
}
a[0] is addressable but b[0] is not.
I know first 0 is an index and second 0 is a key.
Why golang implement like this? Any further consideration?
I've read source code of map in github.com/golang/go/src/runtime and map structure already supported indirectkey and indirectvalue if maxKeySize and maxValueSize are little enough.
type maptype struct {
...
keysize uint8 // size of key slot
indirectkey bool // store ptr to key instead of key itself
valuesize uint8 // size of value slot
indirectvalue bool // store ptr to value instead of value itself
...
}
I think if golang designers want this syntax, it works easy now.
Of course indirectkey indirectvalue may cost more resource and GC also need do more work.
So performance is the only reason for supporting this?
Or any other consideration?
In my opinion, supporting syntax like this is valuable.
As far as I known,
That's because a[0] can be replaced with address of array.
Similarly, a[1] can be replace with a[0]+(keySize*1).
But, In case of map one cannot do like that, hash algorithm changes from time to time based on your key, value pairs and number of them.
They are also rearranged from time to time.
specific computation is needed in-order to get the address of value.
Arrays or slices are easily addressable, but in case of maps it's like multiple function calls or structure look-ups ...
If one is thinking to replace it with what ever computation is needed, then binary size is going to be increased in orders of magnitude, and more over hash algorithm can keep changing from time to time.

Random token generation - a supposedly unlikely collision occurred

A couple months ago, we were using UUIDs to generate random string IDs that needed to be unique across the board. I then changed the algorithm in order to save some data and index space in our database. I tested a few ways to generate unique string IDs, and I decided to use this function:
function generateToken($length) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
$max = strlen($characters) - 1;
$token = '';
for ($i = 0; $i < $length; $i++) {
$token .= $characters[mt_rand(0, $max)];
}
return $token;
}
I'm using this function to generate IDs that are 20 characters long using digits and letters, or you could say these IDs are numbers in base 36. The probability of any 2 IDs colliding should be 1/36^20, but due to the birthday paradox, it can be expected for a collision to occur after about 36^10 records - that's 3.6 quadrillion records. Yet, just a few hours ago a collision occurred, when there were only 5.3 million existing records in the database. Am I extremely unlucky, or my ID-generating function is flawed with respect to randomness? I know mt_rand() isn't truly random, but it is random enough, isn't it?
I would've written a loop that checks if the generated ID is unique and generates a new one if it isn't, but I thought that the chance of getting a collision was so small that the performance cost of such a loop wasn't worth it. I will now include such a loop in the code, but I'm still interested in perfecting the ID generation function if it is indeed flawed.
The implementation of mt_rand() in PHP is rather fluid, so it may differ from one version to the next. However, here are some excerpts from the code used in PHP version 5:
php_rand.h:
/* MT Rand */
#define PHP_MT_RAND_MAX ((long) (0x7FFFFFFF)) /* (1<<31) - 1 */
#ifdef PHP_WIN32
#define GENERATE_SEED() (((long) (sapi_get_request_time(TSRMLS_C) * GetCurrentProcessId())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#else
#define GENERATE_SEED() (((long) (sapi_get_request_time(TSRMLS_C) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))
#endif
PHPAPI void php_srand(long seed TSRMLS_DC);
PHPAPI long php_rand(TSRMLS_D);
PHPAPI void php_mt_srand(php_uint32 seed TSRMLS_DC);
PHPAPI php_uint32 php_mt_rand(TSRMLS_D);
rand.c:
PHP_FUNCTION(mt_rand)
{
long min;
long max;
long number;
int argc = ZEND_NUM_ARGS();
if (argc != 0) {
if (zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) {
return;
} else if (max < min) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "max(%ld) is smaller than min(%ld)", max, min);
RETURN_FALSE;
}
}
if (!BG(mt_rand_is_seeded)) {
php_mt_srand(GENERATE_SEED() TSRMLS_CC);
}
From the last three lines above, you can see that mt_rand() is automatically seeded the first time it is called. However, the php_mt_srand() function takes an argument of type php_uint32. This means there are only 232 possible seeded states for mt_rand(). So if your script runs roughly 216 times, it is quite likely that mt_rand() will produce the exact same sequence of random numbers.
As suggested by rossum, it would be a much better idea to apply AES encryption to an incrementing 128-bit value. If you base64-encode the encrypted results and discard the trailing ==, then the resulting strings will only be 22 characters long.
Addendum
I left the following script running while I was out this afternoon:
for i in $(seq 1 100000) ; do
php -r 'for ($n=0; $n<32; $n++) echo chr(mt_rand(97,122)); echo chr(10);' >>out
done &
As expected, the first collision occurred after about 216 iterations (which is nowhere near 2616):
$ sort <out | uniq -d
vnexqclzkaluntglgadgwzjnjfsvqfhp
$ grep -n vnexqclzkaluntglgadgwzjnjfsvqfhp out
34417:vnexqclzkaluntglgadgwzjnjfsvqfhp
52159:vnexqclzkaluntglgadgwzjnjfsvqfhp
If you want guaranteed unique 16 byte IDs then I would use encryption. AES uses 16 byte (128 bit) blocks and as long as the inputs are unique the outputs are also guaranteed unique.
Set up AES in ECB mode (which is simpler and faster) and encrypt the numbers 0, 1, 2, 3, 4, ... Your inputs are unique so the outputs will be unique as well.
Crypto sites will tell you that ECB mode has security problems, but those problems only apply if the inputs are not unique. For unique 'random' number generation, as you require, those problems do not apply as your inputs are all unique.

Inefficient code: Prevent generation of duplicate random numbers [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have some code from a larger program. This part generate random numbers within a range and checks for duplicates. I have placed print statement to help with getting a handle on scope. If a duplicate is detected I want a new random number to be generated. The code works but I think an experience programmer would laugh at how ineptly it does it. So I was hoping for some guidance on how to improve this code.
Code Extract
-- prepare set of numbers to choose from
local r = {}
for i = c-8, c+12 do
table.insert(r, i)
end
-- take some numbers from the set
for i = 1, #options do
options[i] = table.remove(r, math.random(#r))
end
-- options[] is guaranteed to not contain duplicates
Here's an alternative for when you're only going to pull a few numbers from a large set and place them in options. It might be a tad faster than Egor's in that situation. For the following, assume the random number between integer A and integer B, and you're looking for C unique numbers:
options = {}
local taken = {}
for i = 1,C do
repeat
options[i] = math.random(A,B)
while taken[options[i]] ~= nil
taken[options[i]] = true
end
You can improve it by setting an array to record whether a number has already been added or not. Here is a sample pseudo-code.
//create a list whichs length is the num of possible numbers
numAddedState <- createList((upperBound-lowerBound+1),false)
generatedNums <- []
while length(generatedNums) < requiredLength {
num <- random(lowerBound, upperBound)
if (numAddedState[num - lowerBound]) {
//add the number into list and change the added state of this number to true
generatedNums.append(num)
numAddedState[num - lowerBound] <- true
}
else {
print(num + " is dup")
}
}
return generatedNums
if you need to generate float point numbers, you can replace the numAddedState list with a list of list, which stores grouped numbers. By doing that you can reduce the num of item you need to check.
Here is an example which group numbers using floor()
//create a list whichs length is the num of possible numbers and default value is an empty list
numsAdded <- createList((floor(upperBound)-floor(lowerBound+1)),[])
generatedNums <- []
while length(generatedNums) < requiredLength {
num <- random(lowerBound, upperBound) //generate float point number
for numbers in numsAdded[floor(num)] {
if numbers == num {
print(num + " is dup")
continue
}
}
numsAdded[floor(num)].append(num)
generatedNums.append(num)
}
return generatedNums

Resources