Random rounding to integer in Python

The probability you're looking for is x-int(x).

To sample with this probability, do random.random() < x-int(x)

import random
import math
import numpy as np

def prob_round(x):
    sign = np.sign(x)
    x = abs(x)
    is_up = random.random() < x-int(x)
    round_func = math.ceil if is_up else math.floor
    return sign * round_func(x)

x = 6.1
sum( prob_round(x) for i in range(100) ) / 100.
=> 6.12

EDIT: adding an optional prec argument:

def prob_round(x, prec = 0):
    fixup = np.sign(x) * 10**prec
    x *= fixup
    is_up = random.random() < x-int(x)
    round_func = math.ceil if is_up else math.floor
    return round_func(x) / fixup

x = 8.33333333
[ prob_round(x, prec = 2) for i in range(10) ]
=> [8.3399999999999999,
 8.3300000000000001,
 8.3399999999999999,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3300000000000001,
 8.3399999999999999,
 8.3399999999999999]

Here is a nice one-liner for this. By using the floor function, it will only be rounded up if the random number between 0 and 1 is enough to bring it up to the next highest integer. This method also works with positive and negative numbers equally well.

def probabilistic_round(x):
    return int(math.floor(x + random.random()))

Consider the case of a negative input x = -2.25. 75% of the time the random number will be greater than or equal to 0.25 in which case the floor function will result in -2 being the answer. The other 25% of time the number will get rounded down to -3.

To round to different decimal places it can be modified as follows:

def probabilistic_round(x, decimal_places=0):
    factor = 10.0**decimal_places
    return int(math.floor(x*factor + random.random()))/factor

The most succinct way to do this for non-negative x is:

int(x + random.random())

If for example x == 6.1, then there's a 10% chance that random.random() will be large enough to make x + random.random() >= 7.

Note that if x == 6, then this expression is guaranteed to return 6, because random.random() is always in the range [0, 1).

Update: This method only works for non-negative inputs. For a solution that works for negative numbers, see Chris Locke's answer.