I have written the following C code to recursively solve for a given problem, which is to take in a non-empty list of integers and a target value, and return the closest positive value without going over the target. e.g. (3 4) with target 2 should return 1. The only combination is -3 + 4 = 1.:
int closest(int arr[], int target, int i, int n)
{
if (i == n)
return 0;
int sum1 = arr[i] + closest(arr, target - arr[i], i + 1, n);
int sum2 = -1 * arr[i] + closest(arr, target + arr[i], i + 1, n);
if (abs(sum1 - target) < abs(sum2 - target))
{
return sum1;
}
else
{
return sum2;
}
}
Unfortunately, the problem is meant to be written in Racket, with the restriction of using car + cdr and not using let to create a variable for sum1/sum2 and I'm having major difficulties.
So far:
(define closest (lambda (l target i n)
(cond
((= i n)0)
)
)
)
My question is: how does one convert the arr[i] and pointer to car/cdr logic? I vaguely understand that it controls two values but iterating seems to be breaking my brain in two.
You really should learn how to "think in Scheme", but "thinking in Scheme, in C" can also be valuable.
First, use pointer arithmetic instead of array indexing.
If you squint hard enough, you will see that *p is a bit like (car p) - "the first element" - and p + 1 a bit like (cdr p) - "the rest of the elements".
Then you count down to zero instead of up to n (that is, you ask "how many elements are there left to do?" instead of "how many elements have we done?").
int closest(int *arr, int target, int n)
{
if (n == 0)
return 0;
/* I rearranged these two slightly in order to emphasize the symmetry. */
int sum1 = closest(arr + 1, target - *arr, n-1) + *arr;
int sum2 = closest(arr + 1, target + *arr, n-1) - *arr;
if (abs(sum1 - target) < abs(sum2 - target))
{
return sum1;
}
else
{
return sum2;
}
}
Now we need to get rid of the "let-bindings", sum1 and sum2.
We can do that by introducing a function:
int pick(int target, int sum1, int sum2)
{
return abs(sum1 - target) < abs(sum2 - target) ? sum1 : sum2;
}
int closest(int *arr, int target, int n)
{
if (n == 0)
return 0;
return pick(target,
closest(arr + 1, target - *arr, n-1) + *arr,
closest(arr + 1, target + *arr, n-1) - *arr);
}
(As the Fundamental Theorem says, any problem can be solved by adding a level of indirection.)
This can be formulated in Scheme in a pretty straightforward way - it's mostly a matter of changing the punctuation.
Note that we don't need the counter any more since we can tell from the list itself that we have reached the end:
(define (pick target sum1 sum2)
(if (< (abs (- sum1 target)) (abs (- sum2 target)))
sum1
sum2))
(define (closest arr target)
(if (null? arr)
0
(pick target
(+ (closest (cdr arr) (- target (car arr))) (car arr))
(- (closest (cdr arr) (+ target (car arr))) (car arr)))))
And now we can "inline" pick, removing the target parameter since it's available in the surrounding context:
(define (closest arr target)
(if (null? arr)
0
((lambda (sum1 sum2)
(if (< (abs (- sum1 target)) (abs (- sum2 target))) sum1 sum2))
(+ (closest (cdr arr) (- target (car arr))) (car arr))
(- (closest (cdr arr) (+ target (car arr))) (car arr)))))
Here is a translation of what you are doing. I think the main thing that is tripping you up is how cons car works. "Vectors" (or lists) in racket actually look like this:
(cons 1 (cons 2 (cons 3 empty)))
which translates into this in C
[1, 2, 3]
So how do we get the ith element from it?! Well if you look at your recursion, we don't actually need to. We are, effectively, always getting the next element from the list after the one we just processed. We step through the list one at a time and don't care about what we have already calculated.
Effectively, translated to C, what we are doing in racket is doing pointer arithmetic to get the next element and passing that pointer back into the function as our new arr. The rest of the list is "forgotten" only in the sense we can't access it. Our calculations we have done up to this point are still remembered.
I believe you are using i and n to track where we are in the array so we could remove them since we don't need to actually track which element we are on:
#lang racket
(require test-engine/racket-tests)
(define (closest arr target)
(define sum1 (if (or (null? arr)) 0 (+ (car arr) (closest (cdr arr) (- target (car arr))))))
(define sum2 (if (or (null? arr)) 0 (+ (* -1 (car arr)) (closest (cdr arr) (+ target (car arr))))))
(if (< (abs (- sum1 target)) (abs (- sum2 target)))
sum1
sum2))
(check-expect (closest '(3 4) 2) 1)
(test)
Related
I am trying to find smallest non-divisor of numbers (https://codegolf.stackexchange.com/questions/105412/find-the-smallest-number-that-doesnt-divide-n). Following version using 'named let' works properly:
(define (f1 m)
(let loop ((n 2))
(cond
[(= 0 (modulo m n))
(loop (+ 1 n))]
[else n])))
I am testing with:
(f 24)
(f 1234567)
(f 12252240)
(f 232792560)
Above version produces prompt output of: 5 2 19 and 23.
However, following version which uses built-in for loop is very slow and actually crashes with out of memory error with larger numbers:
(define (f2 m)
(for/first ((i (range 2 m))
#:when (not (= 0 (modulo m i)))
#:final (not (= 0 (modulo m i))))
i))
Is there some error in the code of second version or is for loop inefficient as compared with named let in Racket?
The range function actually allocates a list, so the time for your function is dominated by the huge list allocation. Use in-range instead:
(define (f2 m)
(for/first ([i (in-range 2 m)]
#:when (not (= 0 (modulo m i)))
#:final (not (= 0 (modulo m i))))
i))
See also the section on for performance in the Racket Guide for more notes on the relative speed of different sequence forms.
In my opinion, recursion is generally more well suited for Racket than loops. I'd approach the problem this way...
(define start-counter 1)
(define (f number counter)
(cond [(not (= (modulo number counter) 0)) counter]
[else (f number (add1 counter))]))
(define (f2 number)
(f number start-counter))
In the book Structure and interpretation of computer programs, there is a recursive procedure for computing exponents using successive squaring.
(define (fast-expt b n)
(cond ((= n 0)
1)
((even? n)
(square (fast-expt b (/ n 2))))
(else
(* b (fast-expt b (- n 1))))))
Now in exercise 1.16:
Exercise 1.16: Design a procedure that evolves an iterative exponentiation process that uses successive squaring and uses a logarithmic number of steps,
as does `fast-expt`. (Hint: Using the observation that
(b(^n/2))^2 = (b(^2))^n/2
, keep, along with the exponent n and the base b, an additional state variable a, and define the state transformation in such a way that the product ab^n is unchanged from state to state. At the beginning of the process a is taken to be 1, and the answer is given by the value of a at the end of the process. In general, the technique of defining an invariant quantity that remains unchanged from state to state is a powerful way to think about the design of iterative algorithms.)
I spent a week and I absolutely can't figure how to do this iterative procedure, so I gave up and looked for solutions. All solutions I found is this:
(define (fast-expt a b n)
(cond ((= n 0)
a)
((even? n)
(fast-expt a (square b) (/ n 2)))
(else
(fast-expt (* a b) b (- n 1)))))
Now, I can understand
(fast-expt a (square b) (/ n 2)))
using the hint from the book, but my brain exploded when n is odd. In the recursive procedure, I got why
(* b (fast-expt b (- n 1))))))
works. But in the iterative procedure, it becomes totally different,
(fast-expt (* a b) b (- n 1)))))
It's working perfectly but I absolutely don't understand how to arrive at this solution by myself. it seems extremely clever.
Can someone explain why the iterative solution is like this? And what's the general way to think of solving these types of problems?
2021 update: Last year, I completely forgot about this exercise and the solutions I've seen. I tried solving it and I finally solved it on my own using the invariant provided in the exercise as a basis for transforming the state variables. I used the now accepted answer to verify my solution. Thanks #Óscar López.
Here's a slightly different implementation for making things clearer, notice that I'm using a helper procedure called loop to preserve the original procedure's arity:
(define (fast-expt b n)
(define (loop b n acc)
(cond ((zero? n) acc)
((even? n) (loop (* b b) (/ n 2) acc))
(else (loop b (- n 1) (* b acc)))))
(loop b n 1))
What's acc in here? it's a parameter that is used as an accumulator for the results (in the book they name this parameter a, IMHO acc is a more descriptive name). So at the beginning we set acc to an appropriate value and afterwards in each iteration we update the accumulator, preserving the invariant.
In general, this is the "trick" for understanding an iterative, tail-recursive implementation of an algorithm: we pass along an extra parameter with the result we've calculated so far, and return it in the end when we reach the base case of the recursion. By the way, the usual implementation of an iterative procedure as the one shown above is to use a named let, this is completely equivalent and a bit simpler to write:
(define (fast-expt b n)
(let loop ((b b) (n n) (acc 1))
(cond ((zero? n) acc)
((even? n) (loop (* b b) (/ n 2) acc))
(else (loop b (- n 1) (* b acc))))))
Consider:
(define (factorial x)
(let loop ((x x)
(acc 1))
(if (zero? x)
acc
(loop (sub1 x) (* x acc)))))
I dont understand how does work let here. Moreover, I dont understand this code.
Your example works the same as
(define (factorial x)
(define (loop x acc)
(if (zero? x)
acc
(loop (sub1 x) (* x acc))))
(loop x 1))
which works the same as
(define (factorial x)
(loop x 1))
(define (loop x acc)
(if (zero? x)
acc
(loop (sub1 x) (* x acc))))
To see how the program works, the best advice is to use the stepper in DrRacket.
Since the stepper must be run in the "Intermediate" teaching language, paste this version (note the final example) into DrRacket. Choose the "Intermediate" teaching language and click the stepper button.
(define (factorial x)
(loop x 1))
(define (loop x acc)
(if (zero? x)
acc
(loop (sub1 x) (* x acc))))
(factorial 3)
See also this question for an image that shows the stepper: Fibonacci in Scheme
I need to implement something like this:
(loop for i from 1 to N sum (f i))
except that accumulated values are represent lists of numbers like (1 2 3)
and they are added element-wise. In other words I would like to initialize summation
with (zerov N) and use (v+) to add subsequent elements:
(defun v+ (a b) (mapcar '+ a b))
(defun zerov (n) (loop for i from 1 to n collect 0))
Is it possible to do something like this with loop macro? I can implement it as a
separate function, but I would like to use loop or loop-like macro for expressiveness.
Perhaps there is a way to define simple loop-like macro just for this case?
(loop with accum = (make-list n :initial-element 0)
for i from 1 to n
do (setq accum (v+ accum (f i)))
finally (return accum))
LOOP as defined in the Common Lisp standard is not extensible.
I would write it with the normal LOOP functionality:
(let ((result (zerov n)))
(loop for i from 1 to N
do (setf result (v+ result (f i))))
result)
The I would write it as a function:
(defun sum (n f init sum)
(let ((result (funcall init n)))
(loop for i from 1 to n
do (setf result (funcall sum result (funcall f i))))
result))
If you want such a functionality as a direct language feature of a loopy macro, then an alternative would be the ITERATE macro, which is more powerful than the LOOP macro and it is also extensible.
(reduce #'v+ (loop for i from 1 to n collect (f i))
:initial-value (zerov n))
Note that Common Lisp has proper "vector" (i.e., sequence of elements of homogeneous type allowing more compact representation and efficient random access), so perhaps,
(defun v+ (a b) (map-into a #'+ a b))
(defun zerov (n) (make-array n :initial-element 0))
(defun fn (i n) (let ((v (zerov n))) (setf (aref v i) 1) v))
(defun gn (n)
(loop for v = (zerov n) then (v+ v (fn i n)) for i below n
finally (return v)))
While working on the Clojure Koans, I had to calculate the factorial of a number iterativly, I did find the solution, but I have a question about the difference between 2 solutions, one that works and one that doens't, although I don't understand why:
The one that works:
(defn factorial [n]
(loop [n n
acc 1]
(if (zero? n)
acc
(recur (dec n) (* n acc )))
)
The one that desn't:
(defn factorial [n]
(loop [n n
acc 1]
(if (zero? n)
1
(recur (dec n) (* n acc )))
)
Note that the only difference is the returned value of the If block if the condition is met.
The second factorial function always returns 1. The code is built to use an accumulator variable (acc), and the first code block gets it right by returning this accumulator variable.
A factorial function can be written to return 1, though, if an accumulator variable is not used. Since this method does not utilize loop / recur, it can cause a stack overflow easily: try (fact 5000).
(defn factorial [x]
(if (<= x 1)
1
(* x (factorial (- x 1)))))
(source)
it's hard to work out what you think should be happening for the question to make sense.
i think maybe you think loop is doing more than it does? your code is almost equivalent to:
(defn factorial
([n] (factorial n 1)
([n acc]
(if (zero? n)
acc
(recur (dec n) (* n acc)))))
which is a stack-safe version of
(defn factorial
([n] (factorial n 1)
([n acc]
(if (zero? n)
acc
(factorial (dec n) (* n acc)))))
so the acc (or 1) is the final value returned from the function.
all that loop does is give a different target for recur, which is useful if you have some code between the start of the function and the point where you want to repeat. it's basically a label for a goto.