Reputation: 23
I want to generate a random number with a specific amount of digits (specified by user) and those digits should have a specific sum that has been specified by the user. I have tried assigning a variable to the command random.randint(x,y) and then checking the len() and sum() of that variable if it is equal to the one specified by the user but it hasn't resulted in something useful. The code that I have tried looks something like this:
required_length = input()
required_sum = input()
z = random.randint(0 , 99999)
number = z
length = len(z)
sum1 = sum(int(digit) for digit in str(number))
if length == required_length and sum1 == required_sum:
print(z)
To help if I haven't been specific enough, let's say I want to generate a number that should have 7 digits, and the sum of those 7 digits should be 7. One of those random numbers could be 1121101. I hope this example helped.
See you soon all, and thanks a lot for your help.
Upvotes: 2
Views: 796
Reputation: 26896
The way I would go on this would be to generate a number on a digit by digit basis, where each digit is random within the given constraints.
The idea is that one should pick for a given digit a random number (between 0 and 9 included) except when the outcome could result in a violation of the constraints, in which case the range from which to pick the random number shall be reduced accordingly.
In other words, each digit is picked among the allowed values given the "remaining" sum and number of digits.
To simplify the computation I work on lists of digits and I provide some function to convert from list of digits to integer and viceversa. Note that for incompatible num of digits and sum value, an empty list is produced.
import random
def seq_to_int(seq, base=10):
"""Convert sequence of digits to an integer."""
result = 0
for i, x in enumerate(reversed(seq)):
if 0 <= x < base:
result += x * base ** i
else:
msg = f"Invalid value in `seq` for given `base`"
raise ValueError(msg)
return result
def int_to_seq(n, base=10):
"""Convert an integer to a sequence of digits."""
if n == 0:
return [0]
elif n < 0:
raise ValueError("`n` must be non-negative.")
else:
result = []
while n:
result.append(n % base)
n //= base
return result[::-1]
def random_digits_given_sum(num_digits, sum_value, base=10):
digits = []
max_digit = base - 1
if sum_value > max_digit * num_digits:
return digits
sum_left = sum_value
num_left = num_digits
while num_left > 0:
if sum_left > max_digit:
min_rand = max(0, sum_left - max_digit * (num_left - 1))
max_rand = max_digit
digit = random.randint(min_rand, max_rand)
elif sum_left >= 0 and num_left > 1:
min_rand = 0
max_rand = sum_left
digit = random.randint(min_rand, max_rand)
elif sum_left >= 0 and num_left == 1:
digit = sum_left
else:
raise ValueError
digits.append(digit)
sum_left -= digit
num_left -= 1
# ensure first digit is not 0
if digits[0] == 0:
non_zero_indices = [i for i, digit in enumerate(digits) if digit]
i = random.choice(non_zero_indices)
digits[0], digits[i] = digits[i], digits[0]
# shuffle remaining digits
shuffled = digits[1:]
random.shuffle(shuffled)
return digits[0:1] + shuffled
Below some code to test that it is actually working:
random.seed(0)
n = 2 # number of random inputs to gets
k = 4 # number of different generations
for _ in range(n):
num_digits = random.randint(1, 16)
sum_value = random.randint(1, num_digits * 9)
for _ in range(k):
digits = random_digits_given_sum(num_digits, sum_value)
print(digits, seq_to_int(digits), sum(digits), sum(digits) == sum_value)
with the following output:
[6, 8, 8, 9, 8, 8, 0, 9, 9, 9, 9, 6, 9] 6889880999969 98 True
[5, 9, 4, 7, 9, 5, 6, 9, 9, 9, 8, 9, 9] 5947956999899 98 True
[8, 1, 9, 8, 2, 9, 9, 7, 9, 9, 9, 9, 9] 8198299799999 98 True
[4, 2, 9, 7, 8, 9, 9, 9, 9, 9, 9, 9, 5] 4297899999995 98 True
[6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 4, 9, 9] 699999999999499 127 True
[4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 6, 9] 499999999999969 127 True
[3, 9, 9, 9, 9, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9] 399997999999999 127 True
[9, 7, 5, 9, 9, 9, 9, 9, 8, 9, 8, 9, 9, 9, 9] 975999998989999 127 True
showing that it is working as expected.
Upvotes: 1
Reputation: 2917
You can create a list of numbers which can be generated and then use random.choice()
function to choose 1 element from list.
import random
n = int(input("Amount of digits: "))
x = int(input("Sum of digits: "))
numbers = [num for num in range(10 ** (n - 1), 10 ** n) if sum(map(int, str(num))) == x]
print(random.choice(numbers))
import random
t = []
def f(s, i):
r = sum(map(int, s))
if i == n:
if r == x:
t.append(s)
else:
for q in range(10) if len(s) else range(1, 10):
if r + q <= x:
f(s + str(q), i + 1)
n = int(input("Amount of digits: "))
x = int(input("Sum of digits: "))
f("", 0)
print(random.choice(t))
Upvotes: 1