def binomial_exact(successes, trials, prob):
    """Returns binomial probability of exactly X successes.
    
    Works for integer and floating point values.

    Note: this function is only a probability mass function for integer 
    values of 'trials' and 'successes', i.e. if you sum up non-integer 
    values you probably won't get a sum of 1.
    """
    if (prob < 0) or (prob > 1):
        raise ValueError, "Binomial prob must be between 0 and 1."
    if (successes < 0) or (trials < successes):
        raise ValueError, "Binomial successes must be between 0 and trials."
    return exp(ln_binomial(successes, trials, prob))
 def test_ln_binomial_floats(self):
     """Binomial exact should match values from R for integer successes"""
     expected = {
     (18.3, 100, 0.2): (math.log(0.09089812), math.log(0.09807429)),
     (2.7,1050,0.006): (math.log(0.03615498), math.log(0.07623827)),
     (2.7,1050,0.06): (math.log(1.365299e-25), math.log(3.044327e-24)),
     (2,100.5,0.6): (math.log(7.303533e-37), math.log(1.789727e-36)),
     (0.2, 60, 0.5): (math.log(8.673617e-19), math.log(5.20417e-17)),
     (.5,5,.3):(math.log(0.16807),math.log(0.36015)),
     (10,100.5,.5):(math.log(7.578011e-18),math.log(1.365543e-17)),
     }
     
     for (key, value) in expected.items():
         min_val, max_val = value
         assert min_val < ln_binomial(*key) < max_val
 def test_ln_binomial_range(self):
     """ln_binomial should increase in a monotonically increasing region.
     """
     start=0
     end=1
     step = 0.1
     lower_lim = -1.783375-1e-4
     upper_lim = -1.021235+1e-4 
     previous_value = -1.784
     while start <= end:
         obs = ln_binomial(start,5,.3)
         assert lower_lim <= obs <= upper_lim
         assert obs > previous_value
         previous_value = obs
         start += step
 def test_ln_binomial_integer(self):
     """ln_binomial should match R results for integer values"""
     expected = {
     (10,60,0.1): -3.247883,
     (1, 1, 0.5): math.log(0.5),
     (1, 1, 0.0000001): math.log(1e-07),
     (1, 1, 0.9999999): math.log(0.9999999),
     (3, 5, 0.75): math.log(0.2636719),
     (0, 60, 0.5): math.log(8.673617e-19),
     (129, 130, 0.5): math.log(9.550892e-38),
     (299, 300, 0.099): math.log(1.338965e-298),
     (9, 27, 0.0003): math.log(9.175389e-26),
     (1032, 2050, 0.5): math.log(0.01679804),
     }
     for (key, value) in expected.items():
         self.assertFloatEqualRel(ln_binomial(*key), value, 1e-4)