@@ -805,7 +805,7 @@ which incur interpreter overhead.
805805 if n < 1:
806806 raise ValueError('n must be at least one')
807807 it = iter(iterable)
808- while ( batch := tuple(islice(it, n) )):
808+ while batch := tuple(islice(it, n)):
809809 yield batch
810810
811811 def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
@@ -861,11 +861,23 @@ which incur interpreter overhead.
861861 (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60
862862 """
863863 # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60]
864- roots = list(map(operator.neg, roots))
865- return [
866- sum(map(math.prod, combinations(roots, k)))
867- for k in range(len(roots) + 1)
868- ]
864+ expansion = [1]
865+ for r in roots:
866+ expansion = convolve(expansion, (1, -r))
867+ return list(expansion)
868+
869+ def polynomial_eval(coefficients, x):
870+ """Evaluate a polynomial at a specific value.
871+
872+ Computes with better numeric stability than Horner's method.
873+ """
874+ # Evaluate x³ -4x² -17x + 60 at x = 2.5
875+ # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125
876+ n = len(coefficients)
877+ if n == 0:
878+ return x * 0 # coerce zero to the type of x
879+ powers = map(pow, repeat(x), reversed(range(n)))
880+ return sumprod(coefficients, powers)
869881
870882 def iter_index(iterable, value, start=0):
871883 "Return indices where a value occurs in a sequence or iterable."
0 commit comments