awkrs 0.4.11

Awk implementation in Rust with broad CLI compatibility, parallel records, and experimental Cranelift JIT
Documentation
# Horner's method for polynomial evaluation, plus the synthetic-division
# variant that simultaneously gives p(x) and the quotient polynomial after
# dividing by (x - x0). One line at a time:
#
#   "EVAL a_n a_{n-1} ... a_0  AT x"
#     -> "<poly> at x=<x> = <p(x)>"
#   "DERIV a_n a_{n-1} ... a_0  AT x"
#     -> "<poly>'(x=<x>) = <p'(x)>"   (also via Horner)
#   "DIV   a_n a_{n-1} ... a_0  AT x0"
#     -> "<poly> / (x - x0) = <quot>  rem <p(x0)>"

function horner(coef, n, x,   i, r) {
  r = 0
  for (i = 1; i <= n; i++) r = r * x + coef[i]
  return r
}

function horner_div(coef, n, x0,   i, r, out) {
  delete quot
  r = coef[1]
  quot[1] = r
  for (i = 2; i <= n; i++) {
    r = r * x0 + coef[i]
    quot[i] = r
  }
  # quot[n] is p(x0); quot[1..n-1] are the coefficients of the quotient poly.
  return r
}

function poly_string(coef, n,   i, s, sign, c, exp_) {
  s = ""
  for (i = 1; i <= n; i++) {
    c = coef[i]; exp_ = n - i
    if (c == 0) continue
    if (s == "") {
      s = c "x^" exp_
    } else {
      sign = (c >= 0) ? " + " : " - "
      s = s sign (c < 0 ? -c : c) "x^" exp_
    }
  }
  if (s == "") s = "0"
  return s
}

function quot_string(   i, s, c) {
  s = ""
  for (i = 1; i < cur_n; i++) {
    c = quot[i]
    if (c == 0 && s == "") continue
    if (s == "") s = c "x^" (cur_n - 1 - i)
    else {
      s = s ((c >= 0) ? " + " : " - ") (c < 0 ? -c : c) "x^" (cur_n - 1 - i)
    }
  }
  if (s == "") s = "0"
  return s
}

NF == 0 { next }

{
  cmd = $1
  # Find the "AT" token to split coefficients from x.
  at_idx = 0
  for (i = 1; i <= NF; i++) if ($i == "AT") { at_idx = i; break }
  if (at_idx == 0) { print "missing AT"; next }
  n = at_idx - 2   # number of coefficients
  for (i = 1; i <= n; i++) coef[i] = $(i + 1) + 0
  x = $(at_idx + 1) + 0
  cur_n = n

  if (cmd == "EVAL") {
    v = horner(coef, n, x)
    printf "%s at x=%g = %g\n", poly_string(coef, n), x, v
    next
  }
  if (cmd == "DERIV") {
    delete dcoef
    for (i = 1; i < n; i++) dcoef[i] = coef[i] * (n - i)
    v = horner(dcoef, n - 1, x)
    printf "%s'(x=%g) = %g\n", poly_string(coef, n), x, v
    next
  }
  if (cmd == "DIV") {
    r = horner_div(coef, n, x)
    printf "%s / (x - %g) = %s  rem %g\n", poly_string(coef, n), x, quot_string(), r
    next
  }
}