I am trying to write a program that generates a random number from a random number generated by a Perlin noise. If you ask why I am trying to add a little bit more randomness to a random number generator and see how that would work.
Anyways my problem is from the Perlin noise random number I always get 12 digit random numbers like: 124592051214, 431268750000, 420799999999, 613979257812...
the thing is I want this function to be used just like a normal python Random function. You give the borders(a,b) and you get a random number in those borders.
So, how can I turn a 12 digit number to match the given borders? Thanks in advance
ex:
num = 124592051214
perlinRand(50,100)
62
You can do something like
perlin_noise % (higher-lower) + lower
where "higher" is the higher limit of the random number you want, "lower" is the lower limit and perlin_noise is the number you generate
def perlinRand(lower, higher):
perlin_noise = get_perlin_noise_random_number()
return perlin_noise % (higher-lower) + lower
perlinRand(50, 100)
Related
I tried two different ways to get a coin flip result, seeding the RNG first in order to get reproducible results.
First, I tried using random.randint:
import random
random.seed(23412)
flip = random.randint(0,1)
if flip == 0:
print("Tails")
else:
print("Heads")
For this seed, I get a Heads result; the flip result is 1.
Then, I tried rounding the result of random.random:
import random
random.seed(23412)
flip = random.random()
print(flip) # for testing purposes
new_flip = round(flip)
if new_flip == 0:
print("Tails")
else:
print("Heads")
This time, I get a value for flip of 0.27484468113952387, which rounds to 0, i.e. a Tails result.
Why does the result differ? Shouldn't random.randint pull the same random value (since the seed was the same), and flip the coin the same way?
Seeding a random number generator ensures a reproducible stream of underlying raw data. Different random module methods will compute their results in different ways, using different amounts of data.
The exact computation is an implementation detail. In the implementation I use (although I suspect it is the same for many other versions), random.randint will use the next single bit of raw data from the stream - it does a bunch of math first to figure out how many possible answers there are in range, then rounds that up to the next power of two, then chooses the corresponding number of bits to get a value (0..2n-1), repeats that until it's in range, and finally does more math to scale that to the original range. (If you tried, for example, random.randint(0, 2), it would repeatedly grab two bits interpreted as an integer, until the result isn't 3 which is out of range.)
The implementation of random.random is hidden in the C code, but I assume that it grabs multiple bits of data (at least 53) in order to fill the mantissa of a machine double-precision floating-point value.
Once you set a seed, all random numbers that follow will be consistent. It does not mean that all random numbers will be the same (and not be random any more).
However, once you re-set the seed, the random number generation will start from the beginning. Therefore it's predictable what will happen, e.g. like this, where 200 random numbers are generated in a 100 loops and I can predict each outcome (via assertions)
import random
for i in range(100):
test_seed = 23412
random.seed(test_seed)
flip = round(random.random())
assert flip == 0 # predict "Tails"
if flip == 0:
print("Tails")
else:
print("Heads")
flip = random.randint(0,1)
assert flip == 1 # predict "Heads"
if flip == 0:
print("Tails")
else:
print("Heads")
I've been running some code for an hour or so using a rand.int function, where the code models a dice's roll, where the dice has ten faces, and you have to roll it six times in a row, and each time it has to roll the same number, and it is tracking how many tries it takes for this to happen.
success = 0
times = 0
count = 0
total = 0
for h in range(0,100):
for i in range(0,10):
times = 0
while success == 0:
numbers = [0,0,0,0,0,0,0,0,0,0]
for j in range(0,6):
x = int(random.randint(0,9))
numbers[x] = 1
count = numbers.count(1)
if count == 1:
success = 1
else:
times += 1
print(i)
total += times
success = 0
randtst = open("RandomTesting.txt", "a" )
randtst.write(str(total / 10)+"\n")
randtst.close()
And running this code, this has been going into a file, the contents of which is below
https://pastebin.com/7kRK1Z5f
And taking the average of these numbers using
newtotal = 0
totalamounts = 0
with open ('RandomTesting.txt', 'rt') as rndtxt:
for myline in rndtxt: ,
newtotal += float(myline)
totalamounts += 1
print(newtotal / totalamounts)
Which returns 742073.7449342106. This number is incorrect, (I think) as this is not near to 10^6. I tried getting rid of the contents and doing it again, but to no avail, the number is nowhere near 10^6. Can anyone see a problem with this?
Note: I am not asking for fixes to the code or anything, I am asking whether something has gone wrong to get the above number rather that 100,000
There are several issues working against you here. Bottom line up front:
your code doesn't do what you described as your intent;
you currently have no yardstick for measuring whether your results agree with the theoretical answer; and
your expectations regarding the correct answer are incorrect.
I felt that your code was overly complex for the task you were describing, so I wrote my own version from scratch. I factored out the basic experiment of rolling six 10-sided dice and checking to see if the outcomes were all equal by creating a list of length 6 comprised of 10-sided die rolls. Borrowing shamelessly from BoarGules' comment, I threw the results into a set—which only stores unique elements—and counted the size of the set. The dice are all the same value if and only if the size of the set is 1. I kept repeating this while the number of distinct elements was greater than 1, maintaining a tally of how many trials that required, and returned the number of trials once identical die rolls were obtained.
That basic experiment is then run for any desired number of replications, with the results placed in a numpy array. The resulting data was processed by numpy and scipy to yield the average number of trials and a 95% confidence interval for the mean. The confidence interval uses the estimated variability of the results to construct a lower and an upper bound for the mean. The bounds produced this way should contain the true mean for 95% of estimates generated in this way if the underlying assumptions are met, and address the second point in my BLUF.
Here's the code:
import random
import scipy.stats as st
import numpy as np
NUM_DIGITS = 6
SAMPLE_SIZE = 1000
def expt():
num_trials = 1
while(len(set([random.randrange(10) for _ in range(NUM_DIGITS)])) > 1):
num_trials += 1
return num_trials
data = np.array([expt() for _ in range(SAMPLE_SIZE)])
mu_hat = np.mean(data)
ci = st.t.interval(alpha=0.95, df=SAMPLE_SIZE-1, loc=mu_hat, scale=st.sem(data))
print(mu_hat, ci)
The probability of producing 6 identical results of a particular value from a 10-sided die is 10-6, but there are 10 possible particular values so the overall probability of producing all duplicates is 10*10-6, or 10-5. Consequently, the expected number of trials until you obtain a set of duplicates is 105. The code above took a little over 5 minutes to run on my computer, and produced 102493.559 (96461.16185897154, 108525.95614102845) as the output. Rounding to integers, this means that the average number of trials was 102493 and we're 95% confident that the true mean lies somewhere between 96461 and 108526. This particular range contains 105, i.e., it is consistent with the expected value. Rerunning the program will yield different numbers, but 95% of such runs should also contain the expected value, and the handful that don't should still be close.
Might I suggest if you're working with whole integers that you should be receiving a whole number back instead of a floating point(if I'm understanding what you're trying to do.).
##randtst.write(str(total / 10)+"\n") Original
##randtst.write(str(total // 10)+"\n")
Using a floor division instead of a division sign will round down the number to a whole number which is more idea for what you're trying to do.
If you ARE using floating point numbers, perhaps using the % instead. This will not only divide your number, but also ONLY returns the remainder.
% is Modulo in python
// is floor division in python
Those signs will keep your numbers stable and easier to work if your total returns a floating point integer.
If this isn't the case, you will have to account for every number behind the decimal to the right of it.
And if this IS the case, your result will never reach 10x^6 because the line for totalling your value is stuck in a loop.
I hope this helps you in anyway and if not, please let me know as I'm also learning python.
When generating random integers over (almost) the full interval allowed by int64, the generated integers seem to be generated on a smaller range. I'm using the following code:
import numpy
def randGenerationTest(n_gens=100000):
min_int = 2**63
max_int = 0
for _ in range(n_gens) :
randMatrix = numpy.random.randint(low=1, high = 2**63, size=(1000,1000))
a = randMatrix.min()
b = randMatrix.max()
if a < min_int:
min_int = a
if b > max_int :
max_int = b
return min_int, max_int
Which is returning the following:
randomGenerationTest()
>>> (146746577, 9223372036832037133)
I agree that [1, 146746577] represents just a tiny fraction of the full range I'm trying to get, but in 1e11 random integers generated in the range of [1,2^63), I should have come just once near to my boundaries?
Is this expected behavior when using too large intervals?
Or is it cause as a human I can not grasp how enormous these intervals are and that I am already "near enough"?
By the way, this was just to know if the Seed can be randomly set from 1 to 1e63, as it is possible to set it manually to any of those values.
You're generating 10^3 * 10^3 * 10^5 = 10^11 values. 2^63 / 10^11 ~= 10e+08. You're not even close to filling out the space of values. As a rough back of the hand calculation, if you're sampling 1/10^n elements of a uniform space, the min and max of the sample being ~n order of magnitude from the maximal and minimal element seems pretty reasonable.
The difference of your max. number 9223372036832037133 to the upper boundary of the interval 2**63 - 1 is 22738674. That's only about 2.46e-12 of the full range. The same holds for the min. value 146746577 which has a distance to the lower boundary of about 1.59e-11 relative to the full range of the interval. That means you covered more than 99.999999999% of the interval's range, i.e. pretty much everything.
Trying to create a Random Number Generator that depending on the number outputs a statement. I keep getting the output of Over 50 no matter what. I can't seem to figure out why though.
from random import randrange
print randrange(100)
number = randrange
if number <= 49:
print"Under 50"
else:
print"Over 50"
Changing the following line corrected the issue.
number = randrange(100)
This statement doesn't do what you think:
number = randrange
It's setting number to the function, not to a result from calling the function. If you now did print number(100) you'd see what I mean. Python 2 allows you to compare arbitrary values to each other, even if they're not really comparable, so the <= doesn't fail but doesn't deliver a result that makes sense either. Python 3 would generate an error if you tried to do the same thing.
I was running a procedure to be like one of those games were people try to guess a number between 0 and 100 where there are 100 people guessing.I then averaged how many different guesses there are.
import random
def averager(times):
tests=[]
for i in range(times):
l=[]
for i in range(0,100):
l.append(random.randint(0,100))
tests.append(len(set(l)))
return (sum(tests))/len(tests)
print(averager(1000))
For some reason, the number of different guesses averages out to 63.6
Why is this?Is it due to a flaw in the python random library?
In a scenario where people were guessing a number between 1 and 10
The first person has a 100% chance to guess a previously unguessed number
The second person has a 90% chance to guess a previously unguessed number
The third person has a 80% chance to guess a previously unguessed number
and so on...
The average chance of guessing a new number(by my reasoning) is 55%.
But the data doesn't reflect this.
Your code is for finding the average number of unique guesses made by 100 people each guessing a number from 1 to 100.
As for why it converges to a number around 63... you should post your question to the math Stack Exchange.
If this was a completely flat distribution, you would expect the average to come out as 100, meaning everybody's guess was different. However, you know that such a scenario is much less random than a scenario where you have duplication. The fact that you get repeated numbers during a random sequence should be comforting.
All you are doing here is measuring some kind of uniqueness within very small sets: ie 1000 repeats of an experiment involving 100 random values. You might get a better appreciation of this if you use some sort of bootstrapping algorithm to sample from.
Also, if you scale up the number of repeats to millions, and perhaps measure the sample distribution (not just the mean), you'll have a little more confidence in the results you're getting.
It may be that the pseudo-random generator has a characteristic which yields approximately 60-70% non-repeated values inside a sequence the same length as the range. However, you would need to experiment with far more samples, as well as different random seeds. Otherwise your results are meaningless.
I modified your code so it would take an already generated sequence as input, rather than calculating random numbers:
def averager(seqs):
tests = []
for s in seqs:
tests.append(len(set(s)))
return float(sum(tests))/len(tests)
Then I made a function to return all possible choices for any given number of people and guess range:
def combos(n, limit):
return itertools.product(*((range(limit),) * n))
(One of the things I love about Python is that it's so easy to break apart a function into trivial pieces.)
Then I started testing with increasing numbers:
for n in range(2,100):
x = averager(combos(n, n))
print n, x, x/n
2 1.5 0.75
3 2.11111111111 0.703703703704
4 2.734375 0.68359375
5 3.3616 0.67232
6 3.99061213992 0.66510202332
7 4.62058326038 0.660083322911
8 5.25112867355 0.656391084194
This algorithm has a horrible complexity, so at this point I got a MemoryError. As you can see, the percentage of unique results keeps dropping as the number of people and guess range keeps increasing.
Repeating the test with random numbers:
def rands(repeats, n, limit):
for i in range(repeats):
yield [random.randint(0, limit) for j in range(n)]
for n in range(10, 101, 10):
x = averager(rands(10000, n, n))
print n, x, x/n
10 6.7752 0.67752
20 13.0751 0.653755
30 19.4131 0.647103333333
40 25.7309 0.6432725
50 32.0471 0.640942
60 38.3333 0.638888333333
70 44.6882 0.638402857143
80 50.948 0.63685
90 57.3525 0.63725
100 63.6322 0.636322
As you can see the results are consistent with what we saw earlier and with your own observation. I'm sure a bit of combinatorial math could explain it all.