Goal: split 100
into 5
random 2 decimal place numbers.
So far, I can simulate any number of divisions.
However, these are only integers and are "balanced", in that they are the same or close in values to each other. So, the output is always the same.
Code:
def split(x, n):
if(x < n):
print(-1)
elif (x % n == 0):
for i in range(n):
print(x//n, end =" ")
else:
zp = n - (x % n)
pp = x//n
for i in range(n):
if(i>= zp):
print(pp 1, end =" ")
else:
print(pp, end =" ")
split(100, 5)
>>> 20 20 20 20 20
Desired Output:
- List of numbers,
- Floating point numbers (2 dp),
- Non-balanced.
Example Desired Output:
[10.50, 22.98, 13.23, 40.33, 12.96]
CodePudding user response:
You can use python's builtin random
library to specify random numbers, and keep subtracting that number from your total to generate more random numbers.
Like @Kenny Ostrom suggested, you can multiply by 100 and then divide by 100 at the end to get the desired number of decimal places. I made it more generic by adding a kwarg decimal
, in case you need a different floating point precision
import random
def split(x, n, decimal=2):
if x < n: return -1
if decimal < 0: return -1
x *= 10**decimal
numbers = []
left = x
for i in range(n):
number = random.randint(1,left)
numbers.append(number)
left -= number
return [n / 10**decimal for n in numbers]
Some example outputs
split(100,5) # [1.8, 67.64, 0.51, 21.88, 3.67]
split(100,5) # [29.29, 16.39, 51.54, 1.91, 0.71]
split(100,5) # [95.24, 0.79, 0.82, 2.56, 0.02]
split(100,5) # [10.18, 45.09, 30.87, 0.3, 0.68]
CodePudding user response:
If you generate values uniformly starting with the full range for the first one, the remaining range for the second, the remaining remaining range for the third, etc., there's a 50% chance each time of getting a value larger than half the remaining range. This leads to a systematic bias—on average, earlier values tend to be larger than later values. There's a simple algorithm to avoid this and get identical distributions for all positions:
- Generate a list containing 0 and the maximum value, and then append n-1 values which are all uniformly distributed between 0 and the maximum;
- Sort the list; and
- Calculate the differences between adjacent pairs of values in the sorted list.
By definition the results will add up to the maximum, because they are the interval lengths between 0 and the maximum. Big gaps or small gaps are equally likely to fall between any of the pairs, guaranteeing identical distributions (to the extent that the PRNG is actually uniform).
I've adopted the idea of scaling up by 100 and back to get two decimals. Here it is in code:
import random
def split(x, n, decimal=2):
if x < n: return -1
if decimal < 0: return -1
x *= 10**decimal
numbers = [0, x]
for _ in range(n - 1):
number = random.randint(1, x)
numbers.append(number)
numbers.sort()
return [(numbers[i] - numbers[i-1]) / 10**decimal for i in range(1, n 1)]
which produces outcomes such as
[10.82, 12.97, 17.92, 39.46, 18.83]
[25.99, 21.35, 29.12, 8.13, 15.41]
[5.51, 4.28, 69.59, 9.62, 11.0]
[21.39, 20.96, 11.25, 15.07, 31.33]