Reputation: 518
I'm making a function which adds big numbers together manually (no library function) and I'm having some trouble capturing the result to display. I simply display back '(). Here's a little back ground of how it should work: If I pass (big-add1 '(999) '(456) 0), I should return '(455 1). If I pass (big-add1 '(999 234 681) '(456) 0) I should return '(455 235 681). But I've had no success displaying anything other than the empty list so far. Here's my code right now:
(define (big-add1 x y co)
(cond
;; If both lists are empty, the return value is either 0 or the carryover value.
[(and (= 0 (length x)) (= 0 (length y)))
(if (= co 0) '() (list co))]
[(= 0 (length x)) (big-add1 (list co) y 0)]
[(= 0 (length y)) (big-add1 x (list co) 0)]
[else
(cond(< (length x) (length y)) (big-add1 y x 0)) ;reverse the order of parameters
(append (list(+ (modulo (car x) 10) (modulo (car x) 10) co))) ;trying to construct a result
(if(>(+ (modulo (car x) 10) (modulo (car x) 10) co) 9)
(letrec ([co 1]) co) ;if addition produces a double digit number set carryover value
(letrec ([co 0]) co));if addition produces a single digit number
(if(or(> (car x) 10) (> (car y) 10)) ;we got down to single digits
(big-add1(append(list(quotient (car x) 10)) (cdr x)) (append(list(quotient (car y) 10)) (cdr y)) co)
(big-add1 (cdr x) (cdr y) co))
]
))
(big-add1 '(999) '(456) 0)
(big-add1 '(999 234 681) '(456) 0)
Bonus question: If anyone is feeling up for it, I can see in debug mode that co is not getting changed to 1 when the sum is greater than 10. It seems to execute the line, but not actually change it. Could anyone clarify what is going on? I super new to this, so if anyone has any suggestions on how to simplify it, please feel free to let me know. I would really appreciate it. Thank you for your time.
Upvotes: 3
Views: 697
Reputation: 518
I was able to figure it out by simplifying my algorithm by a lot. Here's what I ended up with:
(define (big-add1 x y co)
(cond
;; If both lists are empty, the return value is either 0 or the carryover value.
[(and (= 0 (length x)) (= 0 (length y)))
(if (= co 0) '() (list co))]
[(= 0 (length x)) (big-add1 (list co) y 0)]
[(= 0 (length y)) (big-add1 x (list co) 0)]
[else
(cons(modulo (+ (car x) (car y) co) 1000)
(if(>(+ (car x) (car y) co) 1000)
(big-add1 (cdr x) (cdr y) 1)
(big-add1 (cdr x) (cdr y) 0))
)
]
))
Upvotes: 0
Reputation: 21
You look like you're in the same class as I am, so I might be able to help out a bit. Takashi Kato above has already answered your question about how racket/scheme returns results (only the last expression will return a result) but I think I can elaborate a bit more on the solution you're trying to get to.
As you've described in your question, the big-add function takes two arguments that are basically a list of "chunks" that represent a number e.g. the list '(999 456)
is handled as a number analogous to 456,999. Each "chunk" within a given list can only have a maximum range from 0 to 999 (assuming we're just adding positive numbers here).
Although Mr. Kato's solution may work, Dr. Austin (if we have the same prof) will prefer that you to complete this problem in a recursive way and return an answer in the same format as the arguments passed in (a list of "chunks"). The lists provided need not be reversed to work.
Here's a way to think about it:
append
or cons
the sums of each chunk together to create a list for returning your result.The algorithm looks kind of like this:
car x
, car y
, and co
together: (+ (car x) (car y) co)
. You can just store this value into an ID by using let
. I called mine chunk-sum
but you can call it whatever makes it easier for you to understand. Within the body of our let
, you'll have to define what to do with our chunk-sum
and how to start creating the list that you return.chunk-sum
is equal to or greater than 1000 or MAX_BLOCK_VALUE
(they are equivalent if you've defined that ID), then there will be a carryover value, so you will want to use a cond
or if
.append
or cons
. I find cons
more preferable for this solution since cons
can take a number element as its first argument, where append
only takes lists (thus requiring you to use list
on chunk-sum
). In this step you will have to recursively call the function big-add1
to continually append elements to your list. Your code for the recursive call will look similar to (big-add1 (cdr x) (cdr y) 0)
if not exactly.So here's the code you'll try to complete:
#lang racket
(define MAX_BLOCK_VALUE 1000)
;; Addition of two big-nums
(define (big-add x y)
(big-add1 x y 0)
)
(define (big-add1 x y co)
(cond
;; If both lists are empty, the return value is either 0 or the carryover value. This is our base case
[(and (= 0 (length x)) (= 0 (length y)))
(if (= co 0) '() (list co))]
[(= 0 (length x)) (big-add1 (list co) y 0)]
[(= 0 (length y)) (big-add1 x (list co) 0)]
[else
#| code is here |#
(let ((chunk-sum (+ (car x) (car y) co)))
(if (>= chunk-sum MAX_BLOCK_VALUE)
;; use cons/append and call recursive step for if we have carryover
(error "foo")
;; use cons/append and call recursive step for if we don't have carryover
(error "bar")
)
)
]
))
Hope this helps.
Upvotes: 2
Reputation: 646
Firstly, there are bunch of mistakes in your code. I'm listing couple of big ones:
else
clause's cond
expression is the typical one not to return.append
does not change the given list's content. It is the ;; trying to...
comment part. Not sure what you wanted to do.letrec
does nothing. If you want to change the bound value, then use set!
.Secondly, the followings are not mistakes but just tips:
append
to create a list. Simply use list
. Using cons
to construct a list then reverse
the result is one of the idiom commonly used to return a list. So if you see using append
, then consider this.null?
procedure to check empty list. If you want to check it using this instead of comparing its length with 0.Finally, following is the one that works as your requirement.
;; each element must be less than 1000 (define (big-add1 x y co) (let loop ((x x) (y y) (co co) (r '())) (cond ;; If both lists are empty, the return value is either 0 ;; or the carryover value. [(and (null? x) (null? y)) ;; if there's carry then we need to add it (if (zero? co) (reverse r) (reverse (cons co r)))] [(null? x) (loop x (cdr y) 0 (cons (+ co (car y)) r))] [(null? y) (loop (cdr x) y 0 (cons (+ co (car x)) r))] [else (let ((r (+ (car x) (car y) co))) ;; add elements ;; separate result into element+carry ;; NB: it's better not to put magic number. (let-values (((e co) (if (> r 1000) (values (modulo r 1000) 1) (values r 0)))) ;; next (loop (cdr x) (cdr y) co (cons e r))))])))
Upvotes: 3