5

Suppose we have a programming language ℤ which has the following syntax:

ℤ := 0 | 1 | (+ ℤ ℤ) | (* ℤ ℤ) | (- ℤ ℤ) | (max ℤ ℤ)

For convenience, we can define new binding forms in our language as follows:

  1. (not x) = (- 1 x)
  2. (abs x) = (- (max 0 (+ x x)) x)
  3. (min x y) = (- 0 (max (- 0 x) (- 0 y)))
  4. (nil x) = (not (min 1 (abs x)))

This language is powerful enough to express branching and comparison operators:

  1. (if x y z) = (+ (* x y) (* (not x) z))
  2. (eq x y) = (nil (- x y))
  3. (ne x y) = (not (eq x y))
  4. (le x y) = (nil (max 0 (- x y)))
  5. (gt x y) = (not (le x y))
  6. (ge x y) = (le y x)
  7. (lt x y) = (not (ge x y))

Now, the question is whether we can define integer division is this language:

  1. (div x y) = ?
  2. (rem x y) = (- x (* y (div x y)))

I don't think that it's possible to define (div x y) because ℤ doesn't have loops. However, I don't know how to prove it. Note that if it's possible then the result of (div x 0) doesn't matter. Hence, either define (div x y) or prove that it's impossible to do so.

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Does ℤ allow recursion? – stf Apr 30 '18 at 18:12
  • No, it doesn't allow recursion. The binding forms are just a convenience. Recursive binding forms aren't allowed. – Aadit M Shah Apr 30 '18 at 18:12
  • I see. I assumed recursion because the syntax uses recursion, and you've assumed `max` as a pre-defined binding. Please edit your question to differentiate between binding forms and legal language strings. – Prune Apr 30 '18 at 18:15
  • @Prune The BNF syntax is recursive. However, it doesn't encode binding forms yet alone recursive binding forms in the language. – Aadit M Shah Apr 30 '18 at 18:17
  • 2
    It's clearly impossible, but I can't see a proof. I guess you'd be better trying at cs.stackexchange. – Paul Hankin Apr 30 '18 at 19:35
  • 1
    Simpler question: can you define `(odd x)` in this language? If not, then there's no hope for `(div x y)`. (I would have asked about `(even x)`, but it looks as though there's an implicit requirement that all function names are three letters long ...) – Mark Dickinson Apr 30 '18 at 19:42
  • @MarkDickinson Yeah, I kind of went overboard with the three letter names. Edited. – Aadit M Shah Apr 30 '18 at 20:06
  • 2
    I believe you should be able to prove (e.g., by structural induction) that any function `f` of a single variable `x` that's expressible in this language is *eventually* a polynomial: that is, there's some integer `x0` and polynomial `p` such that `f(x)` equals `p(x)` for all `x` exceeding `x0`. That should then prove that `(odd x)` is impossible (and hence that `(rem x y)` and `(div x y)` are impossible to construct). – Mark Dickinson Apr 30 '18 at 20:13
  • I agree that it's impossible. We proved it in passing in my college symbolic logic class. I believe we did it by making a four-valued logic system and proving that division is independent of the other operations. – Prune Apr 30 '18 at 20:48
  • It may well be impossible for the particular language you have enunciated here, but if you constructed this language to try to formalize the question "can I implement / with just +, -, *, and comparison?" then the answer to that question is yes. To find a/b, just subtract b from a until you get a number less than b, counting the number of subtractions. – David Wright Apr 30 '18 at 23:31

2 Answers2

5

It's impossible.

Call a function f : Z -> Z eventually polynomial if there exists a polynomial p with integer coefficients and a threshold t such that, for every x > t, we have f(x) = p(x). Let d(x) = [x/2] be floor division by two. d is not eventually polynomial, because the difference sequence of d has infinitely many zeros (f(2y) = y = f(2y+1) for all y), whereas the difference sequence of every non constant polynomial has finitely many. It suffices to show that all implementable functions are eventually polynomial.

The proof proceeds by structural induction. 0 and 1 are polynomial. It's straightforward to show that sums, products, and differences of eventually polynomial functions are eventually polynomial: use the max of the two thresholds and the fact that the set of polynomials is closed under these operations. All that remains is closure under max.

Let f be eventually polynomial via a polynomial p, and g be eventually polynomial via a polynomial q. If p = q, then clearly x |-> max(f(x), g(x)) is eventually polynomial via the same polynomial. Otherwise, observe that p - q has finitely many real roots. Setting the threshold to an upper bound on the roots, we observe that the max function is eventually polynomial via p or q since the other case of the max never triggers here.

David Eisenstat
  • 64,237
  • 7
  • 60
  • 120
0

A combination of recursion and branching will give you loops.

(div x y) = (iff gte(x y) (+ 1 (div((- x y) y))) 0)

In more functional terms, we're doing repeated subtraction. If x >= y, add one to the quotient, subtract y from x, and recur. Otherwise, return 0.

if x >=y
    return 1 + div(x-y y)
else
    return 0
Prune
  • 76,765
  • 14
  • 60
  • 81
  • Yes, but this language doesn't support recursion. Note that you're using `div` within the definition of `div`. That's not allowed. Binding forms aren't a part of the language, yet alone recursive binding forms. They're just a convenience feature to avoid writing long expressions. – Aadit M Shah Apr 30 '18 at 18:10
  • 2
    I see. I assumed recursion because the syntax uses recursion. Please edit your question to differentiate between binding forms and legal language strings. – Prune Apr 30 '18 at 18:13
  • I did. The BNF describes the legal language strings. Before I introduced the binding forms I did mention that they are only for convenience. – Aadit M Shah Apr 30 '18 at 18:15
  • Note that even if ℤ did support recursion, your function would still be wrong. It never terminates if the divisor is a negative integer and is smaller than the dividend, and otherwise it incorrectly returns 0 when the dividend is a negative integer. – Aadit M Shah Apr 30 '18 at 18:55