2
\$\begingroup\$

This is a task I was given for an online course. This is my solution to the problem.

Task: Write a function called general_poly, that meets the specifications below.

For example, general_poly([1, 2, 3, 4])(10) should evaluate to 1234 because

1*10^3 + 2*10^2 + 3*10^1 + 4*10^0

So in the example the function only takes one argument with general_poly([1, 2, 3, 4]) and it returns a function that you can apply to a value, in this case x = 10 with general_poly([1, 2, 3, 4])(10).

def general_poly (L):
    """ L, a list of numbers (n0, n1, n2, ... nk)
    Returns a function, which when applied to a value x, returns the value 
    n0 * x^k + n1 * x^(k-1) + ... nk * x^0 """
    #YOUR CODE HERE 

My Code:

def general_poly (L):
    """ L, a list of numbers (n0, n1, n2, ... nk)
    Returns a function, which when applied to a value x, returns the value
    n0 * x^k + n1 * x^(k-1) + ... nk * x^0 """

    def function_generator(L, x):
        k = len(L) - 1
        sum = 0
        for number in L:
            sum += number * x ** k   
            k -= 1
        return sum

    def function(x, l=L):
        return function_generator(l, x)

    return function
\$\endgroup\$
2
  • \$\begingroup\$ Why do you use L[i] instead of number? \$\endgroup\$ – Arnial Oct 30 '16 at 12:24
  • \$\begingroup\$ wow! Facepalm haha i was stressed when i wrote that, thank you very much lol! \$\endgroup\$ – ChrisIkeokwu Oct 30 '16 at 12:26
7
\$\begingroup\$
  1. The name function_generator could be improved. What this function does is to evaluate the polynomial at the given value x. So a name like evaluate would be better.

  2. The body of function_generator can be simplified. First, it's simpler to iterate over L in reversed order, because then you can start with k = 0 rather than k = len(L) - 1:

    def evaluate(L, x):
        k = 0
        sum = 0
        for number in reversed(L):
            sum += number * x ** k   
            k += 1
        return sum
    

    Now that k goes upwards, you can use enumerate to generate the values for k:

    def evaluate(L, x):
        sum = 0
        for k, a in enumerate(reversed(L)):
            sum += a * x ** k
        return sum
    

    And now that the body of the loop is a single expression, you can use the built-in sum function to do the addition:

    def evaluate(L, x):
        return sum(a * x ** k for k, a in enumerate(reversed(L)))
    

    Another approach to polynomial evaluation is to generate the power series in \$x\$ separately:

    def power_series(x):
        "Generate power series 1, x, x**2, ..."
        y = 1
        while True:
            yield y
            y *= x
    

    and then combine it with the coefficients using zip:

    def evaluate(L, x):
        "Evaluate the polynomial with coefficients in L at the point x."
        return sum(a * y for a, y in zip(reversed(L), power_series(x)))
    

    This is more efficient for large polynomials because each step in power_series is a multiplication by x, which is cheaper to compute than the exponentiation x ** k.

    Finally, you could take advantage of this transformation: $$a_k x^k + a_{k-1} x^{k-1} + \dots + a_1x + a_0 = (\cdots ((0 + a_k)x + a_{k-1})x + \cdots + a_1)x + a_0$$ and write:

    def evaluate(L, x):
        "Evaluate the polynomial with coefficients in L at the point x."
        r = 0
        for a in L:
            r = r * x + a
        return r
    

    (This is Horner's method.)

  3. There's no need for function, because it's fine for the body of function_generator to refer to nonlocal variables like L. So you can write:

    def general_poly(L):
        "Return function evaluating the polynomial with coefficients in L."
        def evaluate(x):
            r = 0
            for a in L:
                r = r * x + a
            return r
        return evaluate
    
  4. An alternative approach is to use functools.partial:

    from functools import partial
    
    def evaluate(L, x):
        "Evaluate the polynomial with coefficients in L at the point x."
        r = 0
        for a in L:
            r = r * x + a
        return r
    
    def general_poly(L):
        "Return function evaluating the polynomial with coefficients in L."
        return partial(evaluate, L)
    

    This would be useful if you sometimes wanted to call evaluate directly (instead of via general_poly).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.