简体   繁体   中英

Split whole number into float numbers

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]

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:

  1. 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;
  2. Sort the list; and
  3. 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]

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]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM