SICP Exercise 1.8 - Why doesn't my function terminate? - scheme

I'm trying to implement Newton's method for cube roots, but my function seems to hang. My code is almost identical to the code the book shows for the square root, with the improve function modified as appropriate.
Here is my code...
(define (cube-root x)
(cube-root-iter 1.0 x))
(define (cube-root-iter guess x)
(if (good-enough? guess x)
guess
(cube-root-iter (improve x guess) x)
)
)
(define (good-enough? guess x)
(< (abs (- (* guess guess) x)) 0.001))
(define (improve x guess)
(/ (+ (/ x (* guess guess)) (* 2 guess)) 3)
)
I tested improve and good-enough? independently, and they seem to give the right answers. Anyone know why my code doesn't terminate?
I'm doing this in Racket with the sicp package in case that makes any difference.

You want to compute the cube root. The cube root of x means a value y for which y*y*y = x, by definition. You try to approximate y using guess, but you compute only y^2. Need to multiply it 3 times:
(define (good-enough? guess x)
(< (abs (- (* guess guess guess) x))
0.001))
If you multiply it only 2 times, y^2 will never get close enough to y^3, which gets closer to x. If you try to compute cube root of 1 or of 0 with your code it might work however (and only for these inputs it might work).

Related

Racket: Trying to subtract numbers, getting list

I'm currently learning Racket/Scheme for a course (I'm not sure what's the difference, actually, and I'm not sure if the course covered that). I'm trying a basic example, implementing the Newton method to find a square root of a number; however, I ran into a problem with finding the distance between two numbers.
It seems that for whatever reason, when I'm trying to apply the subtraction operator between two numbers, it returns a list instead.
#lang racket
(define distance
(lambda (x y) (
(print (real? x))
(print (real? y))
(abs (- x y))
)
)
)
(define abs
(lambda x (
(print (list? x))
(if (< x 0) (- x) x)
)
)
)
(distance 2 5)
As you can see, I've added printing of the types of variables to make sure the problem is what I think it is, and the output of all those prints is #t. So:
In calling distance, x and y are both real.
In calling abs, x is a list.
So, the conclusion is that (- x y) returns a list, but why?
I double-checked with the documentation and it seems I'm using the subtraction operator correctly; I've typed (- 2 5) and then (real? (- 2 5)) into the same REPL I'm using to debug my program (Dr. Racket, to be specific), and I'm getting the expected results (-3 and #t, respectively).
Is there any wizard here that can tell me what kind of sorcery is this?
Thanks in advance!
How about this...
(define distance
(lambda (x y)
(print (real? x))
(print (real? y))
(abs (- x y))))
(define abs
(lambda (x) ;; instead of (lambda x ...), we are using (lambda (x) ...) form which is more strict in binding with formals
(print (list? x))
(if (< x 0) (- x) x)))
Read further about various lambda forms and their binding with formals.

Dr racket define error in student language. define: expected only one expression for the function body, but found 3 extra parts

When I write code in Dr Racket, I got error message
unsaved-editor:8:2: define: expected only one expression for the
function body, but found 3 extra parts in: (define (improve guess x)
(average guess (/ x guess)))
But this code can run in Racket or repl.it.
I want to know why error is happening in Dr Racket and is my code really wrong?
My code is this:
(define (average x y) (/ (+ x y) 2))
(define (square x) (* x x))
(define (sqrt1 x)
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess x)
(average guess (/ x guess)))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
(sqrt-iter 1.0 x))
(sqrt1 9)
Your code is OK for Scheme/Racket. However Student Language is a subset of Scheme, highly limited so it's easier for beginners. It's also used in How To Design Programs book. You can read more about Student Languages (actually there is five of them) on https://docs.racket-lang.org/htdp-langs/index.html.
In case of define there are important limitations:
You can have only one expression in the function body.
In function body you can only use expressions, not definitions (so no define inside define).
To make your code valid for Student Language, depending on Level (Beginner, Intermediate etc), you can:
use letrec* or local instead of define for all local definitions
or
define good-enough, improve and sqrt-iter as top level functions.

Adding the result of computation as an argument in Scheme

I try to do a program that calculates the square of a number in Scheme but it gives me as an error that I gave the abs procedure two arguments instead of one. This is my first program in Scheme and have no clue how to do it. I tried to change the position of the brackets but it doesn't work.
(define (square X)
(try 1 X))
(define (try guess X)
(if (good-enaugh? guess X)
guess
((try improve guess X) X)))
(define (good-enaugh? guess X)
(< (abs(- (* guess guess) X)) 0.0001))
(define (improve guess X)
(/(+ (/ X guess) guess) 2))
You are almost there. The problem is that the second branch of your conditional in try has a pair of parentheses too much.
(define (try guess X)
(if (good-enaugh? guess X)
guess
((try improve guess X) X)))
Should become:
(define (try guess X)
(if (good-enaugh? guess X)
guess
(try (improve guess X) X)))
You make a call to the function try. The first parameter is the result of (improve guess X) and the second argument is the number X. Notice that I also changed the parenthesis around the call to improve. The way you wrote it was calling the function try with as first argument the function improve, second argument guess and third argument X.
Full source
For good measure the complete source is listed below.
(define (square X)
(try 1 X))
(define (try guess X)
(if (good-enaugh? guess X)
guess
(try (improve guess X) X)))
(define (good-enaugh? guess X)
(< (abs(- (* guess guess) X)) 0.0001))
(define (improve guess X)
(/(+ (/ X guess) guess) 2))
> (square 13)
3,....
Link to repl.it

Let Statement/Random Function in Scheme

I was wondering if I would be able to use the built in let function from scheme to define two random variables within the function without their values changing throughout the code. For example if I wrote:
(let (x (- (* 2 (random)) 1)))
(let (y (- (* 2 (random)) 1)))
Would the value of x be constant until the function exits? I want to square x and y and take the square root of them, but I need their values to remain the same.
Yes, let binds a value to the given identifier, and its value doesn't change unless you use set! on it.
So you can do this:
(let ((x (- (* 2 (random)) 1))
(y (- (* 2 (random)) 1)))
(sqrt (+ (* x x) (* y y))))
Of course, I find it easier to define a hypot function for what you're doing (corresponding to C's hypot function):
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
(hypot (- (* 2 (random)) 1)
(- (* 2 (random)) 1))
Now you don't need to use let at all!
In case the connection isn't immediately obvious, the way let works behind the scenes is to create a function (with pretty much the same contents as hypot, in this case), and just calls that function with the values you're binding. So, the two snippets of code above are effectively identical (except that the latter one also adds a top-level binding for hypot).

SICP exercise 1.16, where is my bug, because it looks right to me

I've just started working through this book for fun; I wish it were homework, but I could never afford to attend MIT, and there are tons of people smarter than me anyway. :p
fast-exp is supposed to find b^n, i.e. 4^2 = 16, 3^3 = 27
(define (fast-exp b n)
(define (fast-exp-iter n-prime a)
(cond ((= n-prime 1) a)
((= (remainder n-prime 2) 1) (fast-exp-iter (- n-prime 1) (* a b)))
(else (fast-exp-iter (/ n-prime 2) (* a b b)))))
(fast-exp-iter n 1))
fast-exp 4 2; Expected 16, Actual 2
You forgot to call fast-exp. Instead, you evaluated three separate atoms. To actually evaluate the fast-exp of 4 to the 2, you'd have to write
(fast-exp 4 2)
The solution you have written here is also incorrect. e.g. Check out (fast-exp 2 6). Expected: 64, actual: 32.
Your solution is calculating wrong answers. (See http://ideone.com/quT6A) In fact, how you in principle can write a tail-recursive fast exponentiation passing only two numbers as arguments? I don't think it's even possible, because in the middle of computation you don't know what multiplier to use if you encounter odd exponent.
But I can give an example of working solution that is exactly what is expected by SICP authors (iterative process using "invariant quantity" (a * b^n), where a is initially 1)
(define (pow x y)
(define (powi acc x y)
(cond
((= y 0) acc)
((odd? y) (powi (* acc x) x (- y 1)))
(else (powi acc (* x x) (/ y 2)))))
(powi 1 x y))

Resources