Find the "concise mathematical definition" of a function in SICP - math

Structure and Interpretation of Computer Programs gives this implementation of Ackermann's function:
(define (A x y)
(cond ((= y 0) 0)
((= x 0) (* 2 y))
((= y 1) 2)
(else (A (- x 1) (A x (- y 1))))))
Exercise 1.10 asks for the "concise mathematical definitions" of the following functions that call A:
(define (f n) (A 0 n))
(define (g n) (A 1 n))
(define (h n) (A 2 n))
The outputs of f and g for integers 1 - 4 are recognizable as 2n and 2^n. But h is 2^(2^n-1), a formula I could not recognize just by looking for a pattern in the outputs. How is one meant to complete this exercise? Is there a method for deriving the mathematical notation, perhaps based on the notation for Ackermann's function?

The book has already introduced the substitution method, so it's not wrong to use that.
Start with (A 0 n)
This is
(cond ((= n 0) 0)
((= 0 0) (* 2 n))
((= 0 1) 2)
(else (A (- 0 1) (A 0 (- n 1)))))
which is clearly 2n.
Next, (A 1 n) is
(cond ((= n 0) 0)
((= 1 0) (* 2 n))
((= n 1) 2)
(else (A (- 1 1) (A 1 (- n 1))))))
which is
(A 0 (A 1 (- n 1)))
or, taking advantage of the previous step,
(* 2 (A 1 (- n 1))
That is,
A 1 n = 2 * (A 1 (n-1))
= 2 * 2 * (A 1 (n-2))
= ...
Since we know that A x 1 = 2 for all x, we see that
A 1 n = 2 * 2 * ... * 2
with n factors, i.e. 2n.
Applying similar reasoning to the last case left as an exercise.

Having already figured out that (f n) = (* 2 n) and (g n) = (expt 2 n) we can use that information along with the definition of A to figure out what (A 2 n) will be:
Putting in x=2:
(define (A2 y)
(cond ((= y 0) 0)
((= y 1) 2)
(else (A 1 (A2 (- y 1))))))
Putting in the fact (A 1 n) = (expt 2 n)
(define (A2 y)
(cond ((= y 0) 0)
((= y 1) 2)
(else (expt 2 (A2 (- y 1))))))
from this you can see the recursion pattern more clearly that A2 gives nested powers of two like 2^(2^(2^2)). I think your answer 2^(2^n-1) may be wrong.

You can use scheme itself to help find answers to this:
(define (*^ x y) `(* ,x ,y))
(define (A x y)
(cond ((= y 0) 0)
((= x 0) (*^ 2 y))
((= y 1) 2)
(else (A (- x 1) (A x (- y 1))))))
;> (A 0 100)
;'(* 2 100)
;> (A 0 234)
;'(* 2 234)
suggests (A 0 n) = (* 2 n).
(define (*^ x y) `(* ,x ,y))
(define (A x y)
(cond ((= x 0) (*^ 2 y))
((= y 0) 0)
((= y 1) 2)
(else (A (- x 1) (A x (- y 1))))))
;> (A 1 10)
;'(* 2 (* 2 (* 2 (* 2 (* 2 (* 2 (* 2 (* 2 (* 2 2)))))))))
;> (A 1 5)
;'(* 2 (* 2 (* 2 (* 2 2))))
reordered the rules to avoid an error. we can see its doing *2 n times, so 2^n.
(define (*^ x y) `(* ,x ,y))
(define (A x y)
(cond ((= x 0) (*^ 2 y))
((= x 1) `(expt 2 ,y))
((= y 0) 0)
((= y 1) 2)
(else (A (- x 1) (A x (- y 1))))))
;> (A 2 5)
;'(expt 2 (expt 2 (expt 2 (expt 2 2))))
;> (A 2 6)
;'(expt 2 (expt 2 (expt 2 (expt 2 (expt 2 2)))))
This confirms the idea that we get a tower of exponents.

Related

What is the required recursive function(s) in Scheme programming language to compute the following series?

what is the required recursive function(s) in Scheme programming language to compute the following series?? Explanation needed
1^2/2^1 + 3^4/4^3 + 5^6/6^5 + 7^8/8^7 + 9^10/10^9
So, well, what does each term look like? It's n^(n+1)/(n+1)^n. And you want to stop when you reach 10 (so if n > 10, stop). So write a function of a single argument, n, which either:
returns 0 if n > 10;
adds n^(n+1)/(n+1)^n to the result of calling itself on n + 2.
Then this function with argument 1 will compute what you want. Going backwards may be easier:
return 0 if n < 1;
add n^(n+1)/(n+1)^n to the result of calling itself on n - 2;
then the function with argument 10 is what you want.
Or you could do this which is more entertaining:
(define s
(λ (l)
((λ (c i a)
(if (> i l)
a
(c c
(+ i 2)
(+ a (/ (expt i (+ i 1))
(expt (+ i 1) i))))))
(λ (c i a)
(if (> i l)
a
(c c
(+ i 2)
(+ a (/ (expt i (+ i 1))
(expt (+ i 1) i))))))
1 0)))
But I don't recommend it.
//power function
(define (power a b)
(if (zero? b) //base case
1
(* a (power a (- b 1))))) //or return power of a,b
// sum function for series
(define (sum n)
(if (< n 3) //base case
0.5
(+ (/ (power (- n 1) n) (power n (- n 1))) (sum (- n 2 )) ))) //recursion call
>(sum 10) // call sum function here .

Writing a Division Function in Scheme

I'm trying to create a Division function using only subtraction. What I have so far is enough to handle positive numbers. What keeps tricking me up is handling it for negative numbers. I can go ahead and just grab the absolute value of x and y and it works perfectly, but then my answer can never be negative. Anyone here whose had to do something similar before?
(define Divide (lambda (a b c)
(if (> a 0)
(Divide (- a b) b (+ c 1))
c
)
)
)
You can assign the product of sign values of a and b to a variable, then deal with only absolute values of both a and b while doing the recursion. Output then becomes the product of c and the sign variable as (* c sign). Consider the following:
(define (divide num denom)
(let div ([n num]
[d denom]
[acc 0]
[sign 1])
(cond
[(< n 0)
(div (- n) d acc (- sign))]
[(< d 0)
(div n (- d) acc (- sign))]
[(< n d)
(* sign acc)]
[else
(div (- n d) d (add1 acc) sign)])))
For example,
> (divide 10 7)
1
> (divide -10 7)
-1
> (divide -10 -7)
1
> (divide 10 -7)
-1
Note that if you use the condition (if (> a 0) ... instead of (if (>= a b) ..., then you add an extra step in your recursion, which is why using your function, (Divide 10 7 0) outputs 2.
In cases like this you often want to define an auxiliary function that the main function calls after massaging the data:
(define (Divide a b)
(define (go a b c)
(if (> a 0)
(go (- a b) b (+ c 1))
c))
(cond
[(and (> a 0) (> b 0))
(go a b 0)]
[(and (< a 0) (< b 0))
(go (- a) (- b) 0)]
[(< a 0)
(- (go (- a) b 0))]
[(< b 0)
(- (go a (- b) 0))]))

Recursive call from Condition Branch

I'm starting to get to grips with Lisp and I'm trying to write a procedure to approximate pi using the Leibniz formula at the moment; I think I'm close but I'm not sure how to proceed. The current behavior is that it makes the first calculation correctly but then the program terminates and displays the number '1'. I'm unsure if I can call a defined function recursively like this,
;;; R5RS
(define (pi-get n)
(pi 0 1 n 0))
(define (pi sum a n count)
;;; if n == 0, 0
(if (= n 0) 0)
;;; if count % 2 == 1, + ... else -, if count == n, sum
(cond ((< count n)
(cond ((= (modulo count 2) 1)
(pi (+ sum (pi-calc (+ 2 a))) (+ a 2) n (+ count 1)))
(pi
(- sum (pi-calc (+ 2 a))) (+ a 2) n (+ count 1))))))
(define (pi-calc a)
(/ 1.0 a))
Apologies if this is a little unreadable, I'm just learning Lisp a few weeks now and I'm not sure what normal formatting would be for the language. I've added a few comments to hopefully help.
As Sylwester mentioned it turned out to be a mistake on my part with syntax.
;;; R5RS
(define (pi-get n)
(pi 1 1 n 0))
(define (pi sum a n count)
(if (= n 0) 0)
(cond ((< count n)
(cond ((= (modulo count 2) 1)
(pi (+ sum (pi-calc (+ 2 a))) (+ a 2) n (+ count 1)))
((= (modulo count 2) 0)
(pi (- sum (pi-calc (+ 2 a))) (+ a 2) n (+ count 1))))
(display (* 4 sum)) (newline))))
(define (pi-calc a)
(/ 1.0 a))

recursion in counting the ocurrences of a number

I have found a problem that it says it should be solved by using recursion. The question is that given a certain number it should count the number of 8s that are present in it, but if two 8s are one next to another it should be counted as double. For example:
48 should return 1
4881 should return 4
8818 should return 5
I have made the following program in Scheme:
(define (count n)
(if (= n 0)
0
(begin
(if (= (remainder n 100) 88)
2
(begin
(if (= (remainder n 10) 8)
1
0))
)
(+ (count (quotient n 10))))))
The problem is that everytime I run it returns 0, what am I missing? I do not want to use lists or set! for using an auxiliar variable. Any help?
You have to keep iterating whenever you find a match, and the sums don't seem right. Also, instead of nesting ifs it's better to use cond, like this:
(define (count n)
(cond ((= n 0) 0)
((= (remainder n 100) 88)
(+ 4 (count (quotient n 100))))
((= (remainder n 10) 8)
(+ 1 (count (quotient n 10))))
(else
(+ (count (quotient n 10))))))
It works with your examples:
(count 48)
=> 1
(count 4881)
=> 4
(count 8818)
=> 5
It would be better to count scans of 8s in a helper and keep a current number of hits and a total tally for previous scans.
(define (funny-eights n)
(define (aux n cur total)
(cond ((= (remainder n 10) 8)
(aux (quotient n 10) (+ cur 1) total))
((> cur 1)
(aux (quotient n 10) 0 (+ total (* 2 cur))))
((= cur 1)
(aux (quotient n 10) 0 (+ total cur)))
((> n 0)
(aux (quotient n 10) 0 total))
(else
total)))
(aux n 0 0))
(funny-eights 488838288) ; ==> 11 or 3*2 + 1 + 2*2

Rewrite code to be with less procedures in Scheme

I wrote a program, that given two numbers that specify a range, should return the number (count) of numbers in that range that represented in octal form consist of a number of identical digits. For example 72->111 meets this criteria, because all the digits are the same. Examples of output:
(hw11 1 8) -> 7,(hw11 1 9) -> 8,(hw11 1 18) -> 9,(hw11 1 65) -> 14, and so on...
My problem is that to be correct my program must define only 2 procedures, and at the moment I have much more than that and have no idea how to make them less. So any help with rewriting the code is welcomed :). The code is below:
(define (count-digits n)
(if (<= n 0)
0
(+ 1 (count-digits (quotient n 10)))))
(define (toOct n)
(define (helper n octNumber i)
(if(<= n 0)
octNumber
(helper (quotient n 8)
(+ octNumber
(* (expt 10 i)
(remainder n 8)))
(+ i 1))))
(helper n 0 0))
(define (samedigits n)
(define (helper n i)
(if (<= n 0)
#t
(if (not (remainder n 10) i))
#f
(helper (quotient n 10) i))))
(helper n (remainder n 10))
)
(define (hw11 a b)
(define (helper a x count)
(if (> a x)
count
(if (samedigits (toOct x))
(helper a (- x 1) (+ count 1))
(helper a (- x 1) count))))
(helper a b 0))
You probably have restrictions and you didn't state which Scheme implementation you're using; the following is an example that has been tested on Racket and Guile:
(define (hw11 a b)
(define (iter i count)
(if (<= i b)
(let* ((octal (string->list (number->string i 8)))
(allc1 (make-list (length octal) (car octal))))
(iter (+ i 1) (if (equal? octal allc1) (+ count 1) count)))
count))
(iter a 0))
Testing:
> (hw11 1 8)
7
> (hw11 1 9)
8
> (hw11 1 18)
9
> (hw11 1 65)
14

Resources