The Binomial Form of a polynomial has many uses, just as the standard form does.  For comparison, if p(x) is in Binomial Form and q(x) is in standard form, we might write

p(x) := a0 \* xC0 + a1 \* xC1 + a2 \* xC2 + ... + aN \* xCN

q(x) := b0 + b1 \* x + b2 \* x^(2) + ... + bN \* x^(N)

Both forms have tricks for evaluating them, but tricks should not be necessary.  The most important thing to keep in mind is that aCb can be defined for non-integer values of a; in particular,

```
aCb := a * (a-1) * (a-2) * ... * (a-b+1) / b!   // for any value a and integer values b
    := a! / ((a-b)!b!)                          // for integer values a,b
```

The inputs to your function are an array which specifies a polynomial in Binomial Form, ordered by highest-degree-first, and also a number to evaluate the polynomial at.  An example call might be

```python
value_at([1, 2, 7], 3)
```

and the return value would be 16, since 3C2 + 2 * 3C1 + 7 = 16.  In more detail, this calculation looks like

```
1 * xC2 + 2 * xC1 + 7 * xC0 :: x = 3
3C2 + 2 * 3C1 + 7
3 * (3-1) / 2! + 2 * 3 / 1! + 7
3 + 6 + 7 = 16
```

More information can be found by reading about [Binomial Coefficients](https://en.wikipedia.org/wiki/Binomial_coefficient) or about [Finite Differences](https://en.wikipedia.org/wiki/Finite_difference).

Note that while a solution should be able to handle non-integer inputs and get a correct result, any solution should make use of rounding to two significant digits (as the official solution does) since high precision for non-integers is not the point here.

Difficulty: introductory

Starter code:

def value_at(poly_spec, x):
	

Solutions:
from functools import reduce
from math import factorial


def value_at(poly, x):
    return round(sum(n * aCb(x, i) for i, n in enumerate(poly[::-1])), 2)

def aCb(a, b):
    return reduce(lambda x, y: x * y, (a - i for i in range(b)), 1) / factorial(b)


def aCb(a, b):
    result = 1.0
    for i in range(b):
        result = result * (a - i) / (i + 1)
    return result

def value_at(poly_spec, x):
    answer = 0
    l = len(poly_spec)
    for i, coeff in enumerate(poly_spec):
        answer += coeff * aCb(x, l - i - 1)
    return round(answer, 2)

from math import factorial
from functools import reduce

def product(seq):
    return reduce(lambda x,y:x*y, seq) if seq else 1

def comb(x, r):
    return product([x - i for i in range(r)]) / factorial(r)

def value_at(p, x):
    result = sum(a*comb(x, i) for i, a in enumerate(p[::-1]))
    
    return result if isinstance(x, int) else round(result, 2)


def binom(x, k):
    r = 1
    for i in range(1, k + 1):
        r *= (x - i + 1) / i
    return r

def value_at(poly_spec, x):
    r = 0
    for k, c in enumerate(poly_spec[::-1]):
        r += c * binom(x, k)
    return round(r, 2)

from math import factorial
from functools import lru_cache

factorial = lru_cache(maxsize=None)(factorial)

def comb(a, b):
    if isinstance(a, int):
        return int(factorial(a) / factorial(b) / factorial(max(0, a - b)))
    r = 1
    for i in range(b):
        r *= a - i
    return r / factorial(b)

def value_at(a, n):
    return round(sum(x * comb(n, i) for i, x in enumerate(a[::-1])), 2)

def value_at(poly_spec, x):
    leng = len(poly_spec)
    ans = 0
    for i, e in enumerate(poly_spec):
        temp = 1
        for j in range(leng-i-1):
            temp *= (x-j)/(j+1)
        ans += e*temp
    return round(ans, 2)

value_at=lambda p, x: round(sum(map(lambda e: e[1]*c(x,e[0]), enumerate(p[::-1]))), 2)
c=lambda x,b: 1 if x==b or b<1 else x if b<2 else x*c(x-1,b-1)/b

def value_at(poly_spec, x):
    if len(poly_spec) < 2: return poly_spec[0] if poly_spec else 0
    l = len(poly_spec) - 1
    m = [co * binomial(x, l - i) for i, co in enumerate(poly_spec[:-1])]
    return round(float(sum(m) + poly_spec[l]), 2)
    
def factorial(n):
    return 1 if n < 2 else n * factorial(n - 1)
    
def binomial(a, b): 
    res = 1.0
    for k in range(b): res *= (a - k)
    return res / factorial(b)

def comb(a,b):
    r=1
    s=1
    for i in range(1,b+1):
        r*=(a-i+1)
        s*=i
    return r/s

def value_at(poly_spec, x):
    r=0
    for i,c in enumerate(poly_spec[::-1]):
        r+=c*comb(x,i)
    return round(r,2)

def value_at(p, x):
    return round(sum(c * choose(x,len(p)-1-i) for i,c in enumerate(p)), 2)
    
def choose(x, k):
    n,d = 1,1
    for i in range(k): n, d = n*(x-i), d*(i+1)
    return n / d