Python randint generates numbers with the same number of digits - python

for i in range(number_of_numbers):
randomNumber = randint(1, pow(10, numberPower))
numbers.append(randomNumber)
numbersIncreasing.append(randomNumber)
So I'm making a little math game that generates n amount of numbers from user input. This is the code that generates the numbers and appends them to a list. The only problem is, is it gives numbers with the same amount of digits, which is whatever numberPower is set to (12). An example would be two numbers like 9,564,713,666,123 or 1,256,286,233,753, and all the numbers have 12 digits. I was expecting more very mixed numbers, that could literally be anywhere between 1 and 10^12.

This is because most numbers between 1 and 10**12 have 12 digits. Specifically, 90% of numbers between 1 and 10^12 have 12 digits. Then 9% have 11 digits; only 1% have 10 digits or less.
9 numbers have 1 digit (1-9);
90 numbers have 2 digits (10-99);
900 numbers have 3 digits (100-999);
9000 numbers have 4 digits (1000-9999);
...
9 * 10**10 numbers have 11 digits (10000000000-99999999999);
9 * 10**11 numbers have 12 digits (100000000000-999999999999);
1 number has 13 digits (1000000000000).
If you want, you can try to draw a histogram showing how many numbers have how many digits, when randomly generating a large number of numbers between 1 and 10**12:
import random
import matplotlib.pyplot as plt
X = [random.randint(1,10**12) for _ in range(10000)]
nb_digits = [len(str(x)) for x in X]
plt.hist(nb_digits, bins=range(1,14), density=True)
plt.show()
Another way to think about it: leading zeroes
Generating a number uniformly at random between 0 and 10**12 - 1 is the same as generating 12 digits uniformly at random between 0 and 9, and concatenating them to write a number in base 10.
The "number of digits" of the resulting number will be 12 minus the number of leading zeroes.
For instance, the string 000000049608 counts as a 5-digit number, because the first 7 digits are zeroes.
Thus, if the leftmost digit generated is not a 0, then the resulting number will count as a 12-digit number. This happens whenever the first digit is 1,2,3,4,5,6,7,8 or 9, which is 90% of the time.
What is the probability to get a number with 5 digits or less, like above? It's the probability that the leftmost 7 digits are all zeroes. The probability that this happens is (1/10)**7 = 0.00001%. As you can see, most numbers don't have a lot of leading zeroes.
If you want to skew the distribution to get more diversity in number of digits
Maybe you don't want your random numbers to follow a uniform distribution? Try this:
import random
number_of_numbers = 100
numberPower = 12
numbers = []
for _ in range(100):
randomNumberOfDigits = random.randint(1, numberPower)
randomNumber = random.randint(10**(randomNumberOfDigits - 1), 10**randomNumberOfDigits - 1)
numbers.append(randomNumber)
print(numbers)
# [4, 42, 6004, 2, 46111, 2023179648, 41991462, 525, 2412, 221700769, 47, 5304427, 102, 23, 54323975, 906, 894363079057, 556, 675354, 9365725, 838, 490947621, 82648961, 9232330, 2885693, 28889965, 31601, 505250081, 534874, 85, 4630, 5, 8088582, 67921960, 722774315903, 16, 33, 7752943, 16628713055, 74, 2561429212, 67626556043, 155962, 596, 8655352595, 4735, 7, 8296258, 17722, 78, 93044214350, 17247469, 58295330, 622, 332, 450232321717, 70292459, 11, 447064711120, 895793, 8, 540110, 43032518210, 7, 20361, 606, 9, 9943927, 983, 54327, 40473362991, 2358, 7102932592, 15960846, 99385316379, 88654316391, 219692155, 3732404, 5474, 6343805291, 74, 844532493412, 2, 45228, 186785825, 10704, 4833, 744164008354, 976046952, 7836, 49344611762, 34985277, 362, 49577, 868571104, 237506, 2, 920019513002, 83847, 77908803]
Note: I chose to write ** for power instead of ^, because we're illustrating with python code and in python, ** means power while ^ means something entirely different.

Related

How can I make all possible list combinations using reversible seeds?

I want to have a list made out of 100 items, each item being a value from 0-31 inclusive. I then want to be able to take one of these lists, and know what seed/input is necessary to randomly generate that exact list.
Using some suitable Linear Congruential Generator:
You could use this research paper by Pierre L'Ecuyer:
Tables_of_linear_congruential_generators_of_different_sizes_and_good_lattice_structure
The lowest power of 2 modulus for which the paper gives examples of (decently pseudo-random) LCGs is 230, which is close to 1 billion. See table 4 of the paper. Just pick one of those LCGs, say:
un+1 = ((116646453 * un) + 5437) mod 230
Each of your items is exactly 5 bits wide. If you decide to group your items 6 by 6, each group is exactly 30 bits wide, so can be considered as one state of this modulo 230 LCG.
From a initial group of 6 items, one step of the LCG will generate the next group, that is the next 6 items. And the paper tells you that the serie will look reasonably random overall.
Hence, you can regard the first 6 items as your “seed”, as you can reconstruct the whole list from its leftmost 6 items.
Even assuming that for the sake of obfuscation you started the visible part of the list after the seed, you would still have only about one billion possible seeds to worry about. Any decent computer would be able to find the left-hidden seed by brute force within a handful of seconds, by simulating the LCG for every possible seed and comparing with the actual list.
Sample Python code:
One can start by creating a class that, given a seed, supplies an unlimited serie of items between 0 and 31:
class LEcuyer30:
def __init__ (self, seed):
self.seed = seed & ((1 << 30) - 1)
self.currGroup = self.seed
self.itemCount = 6
def __toNextGroup(self):
nextGroup = ((116646453 * self.currGroup) + 5437) % (1 << 30)
self.currGroup = nextGroup
self.itemCount = 6
def getItem(self):
if (self.itemCount <= 0):
self.__toNextGroup()
# extract 5 bits:
word = self.currGroup >> (5 * (self.itemCount - 1))
self.itemCount -= 1
return (word & 31)
Test code:
We can create a sequence of 20 items and print it:
# Main program:
randomSeed = 514703103
rng = LEcuyer30(randomSeed)
itemList = []
for k in range(20):
item = rng.getItem()
itemList.append(item)
print("itemList = %s" % itemList)
Program output:
itemList = [15, 10, 27, 15, 23, 31, 1, 10, 5, 15, 16, 8, 4, 16, 24, 31, 7, 5, 8, 19]

Randomnly select numbers from a list with a condition

I have a list(range(30000)). I need to randomnly select numbers inside it such that, it takes a certain count of numbers say 'n' in total at the same time it should take 'k' number of values between two index positions.
For example:
a = [1,2,3,4,5,,6,7,8......20,21,22......88,89.....30k]
I need to select 5000 numbers in total. 'x' numbers between 0th index to 100th index, 'y' numbers between 100 to 200 etc.
There is no hard rule that it should select 5000 numbers itself. But it should sure lie between 0-100, 100-200 etc.
I saw random.choice but how to give it a condition
To put the question accurately: I need 50 numbers from 0-100,200-300 etc.
Here's one way to approach this:
import random
# define the sample size of each interval
# or for your specific case generate a sequence
# that adds up to 5000
size = [5, 2, 10]
n = 300
step = 100
# iterate over both a range (or sequence) and size
# and take random samples accordingly
out = [random.sample(list(range(i-step,i)), k)
for i, k in zip(range(step, n+step, step), size)]
print(out)
[[6, 86, 96, 62, 53], [115, 176], [245, 259, 297, 249, 225, 281, 264, 274, 275, 206]]
This is a simple script that does exactly what you asked for.
import random
a = 0
b=100
l = list()
for z in range(149):
a = a+200
b = b+200
for x in range(50):
l.append(random.randint(a,b))

Python -personal Identification number

Im trying to code a personal identificational number which should have 10 numbers. It looks like this 990830/4197.
First two numbers - year - 1999 he was born
Second two numbers - month - august
Third two numbers - day 3O.8
Last 4 numbers are generated that way so the whole number when you take it has to be devided by 11 and there cant remain any number. So for example;
99+8+30+4197= 4 334 /11 = 394.
Always the number should be % = 0.
I wanna ask for some key words that might help me when I wanna generate correct numbers.
Thanks
I am assuming here that the date part of the number you have already. Then you can use this code to calculate the "tail" efficiently:
from random import randint
date = 990830
s = sum(int(x) * 10**(i % 2) for i, x in enumerate(str(date), 1)) # note 1
tail = randint(90, 908) * 11 - (s % 11) # note 2
print('{}\{}'.format(date, tail))
which produces (several examples):
990830\5462
990830\5132
990830\8751
990830\6397
with all of them being perfectly divisible by 11.
This simply adds the numbers of the date as described (e.g., 99 + 08 + 30)
This calculates a random 4 digit number that when added to the above sum creates a number N for which N % 11 == 0.

what are the possible permutations of 8 digits

I need to know what are the possible permutations of 8 digits following the rules of my python code:
import itertools
import time
import string
numbers = set(range(10))
letters = set(string.ascii_letters)
mylist=[]
start=time.time()
comb = ([x for x in itertools.combinations([0,1,2,3,4,5,6,7,8,9,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'], 8)
if set(x) & letters and set(x) & numbers])
f=open("data.txt","w")
f.write("%s" % comb)
f.close()
end=time.time()
diff=end-start
print ("Se obtuvieron {} combinaciones.".format(len(comb)))
print ("En un tiempo total de:",diff,"segundos")
There's a lot of them. To be clear:
Combinations of 123 for 2 digits are 12, 13, 23.
Permutations of 123 for 2 digits are 12, 13, 21, 23, 31, 32.
Combinations is a smaller number because order doesn't matter. Your code looks like you require at least one number or letter in your 8-digit combination, so you need the sum of:
Combinations of 1 digit times combinations of 7 letters.
Combinations of 2 digits times combinations of 6 letters.
etc...
Combinations of 7 digits times combinations of 1 letter.
Permutations should be 62 letters/numbers taken 8 at a time, minus the all-letter permutations of 52 letters taken 8 at a time, minus the all-number permutations of 10 numbers taken 8 at a time.
from math import factorial as f
def P(n,k):
return f(n)//f(n-k)
def C(n,k):
return f(n)//f(n-k)//f(k)
letters = 52
numbers = 10
length = 8
combinations = sum(C(numbers,i) * C(letters,length-i) for i in range(1,length))
print('Combinations: {:20,}'.format(combinations))
permutations = P(letters+numbers,length) - P(letters,length) - P(numbers,length)
print('Permutations: {:20,}'.format(permutations))
Output:
Combinations: 2,628,560,350
Permutations: 105,983,553,312,000
Trying to generate all those combinations or permutations in an in-memory list as your code is doing is not a good idea.
For the record, I don't think you are asking the right question. You say permutation, but your code uses combinations, those are different things.
I will not give you the complete answer, because it would take forever to compute that. To put it in perspective just how big this number is. The permutation of 8 numbers from 0~9 is: 1.814.400
Starting with: (0, 1, 2, 3, 4, 5, 6, 7), ending in (9, 8, 7, 6, 5, 4, 3, 2)
You can demonstrate how many permutation of 8 there's in all the ASCII letters with the numbers from 0~9 using this:
mylist = range(10)
mylist.extend(ascii_letters)
i = 0
for n in permutations(mylist,8):
i += 1
But this will take VERY LONG, just to show how big this number is:
I ran it for a couple of minutes and it was over 1.500.000.000.( 1.5 billion )
Also, your code doesn't make much sense. Why do you need to calculate such big number? Why do you need to write it to a file(it will probably take forever/run out memory and/or space). Try elaborating what you want.

Sum of Digits, properties, hint please

This is the problem:
How many integers 0 ≤ n < 10^18 have the property that the sum of the digits of n equals the sum of digits of 137n?
This solution is grossly inefficient. What am I missing?
#!/usr/bin/env python
#coding: utf-8
import time
from timestrings import *
start = time.clock()
maxpower = 18
count = 0
for i in range(0, 10 ** maxpower - 1):
if i % 9 == 0:
result1 = list(str(i))
result2 = list(str(137 * i))
sum1 = 0
for j in result1:
sum1 += int(j)
sum2 = 0
for j in result2:
sum2 += int(j)
if sum1 == sum2:
print (i, sum1)
count += 1
finish = time.clock()
print ("Project Euler, Project 290")
print ()
print ("Answer:", count)
print ("Time:", stringifytime(finish - start))
First of all, you are to count, not to show the hits.
That is very important. All you have to do is to device an efficient way to count it. Like Jon Bentley wrote in Programming Pearls: "Any methond that considers all permutations of letters for a word is doomed to failure". In fact, I tried in python, as soon as "i" hit 10^9, the system already freezed. 1.5 G memory was consumed. Let alone 10^18. And this also tells us, cite Bentley again, "Defining the problem was about ninety percent of this battle."
And to solve this problem, I can't see a way without dynamic programming (dp). In fact, most of those ridiculously huge Euler problems all require some sort of dp. The theory of dp itself is rather academic and dry, but to implement the idea of dp to solve real problems is not, in fact, the practice is fun and colorful.
One solution to the problem is, we go from 0-9 then 10-99 then 100-999 and so on and extract the signatures of the numbers, summarize numbers with the same signature and deal with all of them as a piece, thus save space and time.
Observation:
3 * 137 = 411 and 13 * 137 = 1781. Let's break the the first result "411" down into two parts: the first two digits "41" and the last digit "1". The "1" is staying, but the "41" part is going to be "carried" to further calculations. Let's call "41" the carry, the first element of the signature. The "1" will stay as the rightest digit as we go on calculating 13 * 137, 23 * 137, 33 * 137 or 43 * 137. All these *3 numbers have a "3" as their rightest digit and the last digit of 137*n is always 1. That is, the difference between this "3" and "1" is +2, call this +2 the "diff" as the second element of the signature.
OK, if we are gonna find a two-digit number with 3 as its last digit, we have to find a digit "m" that satisfies
diff_of_digitsum (m, 137*m+carry) = -2 (1)
to neutralize our +2 diff accumulated earlier. If m could do that, then you know m * 10 + 3, on the paper you write: "m3", is a hit.
For example, in our case we tried digit 1. diff_of_digitsum (digit, 137*digit+carry) = diff_of_digitsum (1, 137*1+41) = -15. Which is not -2, so 13 is not a hit.
Let's see 99. 9 * 137 = 1233. The "diff" is 9 - 3 = +6. "Carry" is 123. In the second iteration when we try to add a digit 9 to 9 and make it 99, we have diff_of_digitsum (digit, 137*digit+carry) = diff_of_digitsum (9, 137*9+123) = diff_of_digitsum (9, 1356) = -6 and it neutralizes our surplus 6. So 99 is a hit!
In code, we just need 18 iteration. In the first round, we deal with the single digit numbers, 2nd round the 2-digit numbers, then 3-digit ... until we get to 18-digit numbers. Make a table before the iterations that with a structure like this:
table[(diff, carry)] = amount_of_numbers_with_the_same_diff_and_carry
Then the iteration begins, you need to keep updating the table as you go. Add new entries if you encounter a new signature, and always update amount_of_numbers_with_the_same_diff_and_carry. First round, the single digits, populate the table:
0: 0 * 137 = 0, diff: 0; carry: 0. table[(0, 0)] = 1
1: 1 * 137 = 137. diff: 1 - 7 = -6; carry: 13. table[(-6, 13)] = 1
2: 2 * 137 = 274. diff: 2 - 7 = -5; carry: 27. table[(-5, 27)] = 1
And so on.
Second iteration, the "10"th digit, we will go over the digit 0-9 as your "m" and use it in (1) to see if it can produce a result that neutralizes the "diff". If yes, it means this m is going to make all those amount_of_numbers_with_the_same_diff_and_carry into hits. Hence counting not showing. And then we can calculate the new diff and carry with this digit added, like in the example 9 has diff 6 and carry 123 but 99 has the diff 9 - 6 ( last digit from 1356) = 3 and carry 135, replace the old table using the new info.
Last comment, be careful the digit 0. It will appear a lot of times in the iteration and don't over count it because 0009 = 009 = 09 = 9. If you use c++, make sure the sum is in unsigned long long and that sort because it is big. Good luck.
You are trying to solve a Project Euler problem by brute force. That may work for the first few problems, but for most problems you need think of a more sophisticated approach.
Since it is IMHO not OK to give advice specific to this problem, take a look at the general advice in this answer.
This brute force Python solution of 7 digits ran for 19 seconds for me:
print sum(sum(map(int, str(n))) == sum(map(int, str(137 * n)))
for n in xrange(0, 10 ** 7, 9))
On the same machine, single core, same Python interpreter, same code, would take about 3170 years to compute for 18 digits (as the problem asked).
See dgg32's answer for an inspiration of a faster counting.

Categories