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.

Source: codewars | Difficulty: EASY
Tags: Fundamentals

Mathematics

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