Index: List of bits example, define-struct
In high school, you probably learned about binary numbers. If not, we will briefly review them. A binary number (or, number in base two) consists of only 0's and 1's, rather than 0's through 9's, as in decimal numbers. The right-most binary digit ("bit") represents the number of ones counted, the next-right-most bit represents the number of twos counted, and further bits represent increasing powers of two. E.g., 10110 (binary) = 16*1 + 8*0 + 4*1 + 2*1 + 1*0 = 22 (decimal).
We will represent binary numbers as a list of bits. Our data definitions are A Bit is either
We already have the functions zero?, null?, and cons?. It's convenient to also define
(define one? (lambda (b) (= b 1)))
The "meaning" of a list of bits is as follows:
Note that the list represents the binary number backwards. E.g., the binary number 10110 is represented by (cons 0 (cons 1 (cons 1 (cons 0 (cons 1 null))))). Furthermore, the above meaning says that this list represents the value 0 + 2(1 + 2(1 + 2(0 + 2(1 + 0)))) = 22, as expected.
We can do this much without even knowing what we are trying to write:
;; (define lob-function ;; (lambda (lob) ;; (cond ((null? lob) ...) ;; (else ...(car lob)...(lob-function (cdr lob))... ))))
Since there are two possibilities for (first lob), namely 0 and 1, we should also define a template for Bits, and use it:
;; (define bit-function ;; (lambda (b) ;; (cond ((zero? b) ...) ;; (else ...)))) ;; ;; (define lob-function ;; (lambda (lob) ;; (cond ((null? lob) ...) ;; (else ...(bits-function (car lob))... ;; ...(lob-function (cdr lob))... ))))
We can use our program templates to guide us in defining functions on Lists of Bits, e.g, log->num, addone, and subone.
Functions to convert a list of bits into a number follow from our "meaning" we gave before:
(define bit->num (lambda (b) (cond ((zero? b) b) (else b)))) (define lob->num (lambda (lob) (cond ((null? lob) 0) (else (+ (bit->num (first lob)) (* 2 (lob->num (cdr lob))))))))
The program templates led us to write a correct program. But, now observe that we can easily simplify it:
(define lob->num (lambda (lob) (cond ((null? lob) 0) (else (+ (first lob) (* 2 (lob->num (cdr lob))))))))
Going the other direction, converting a number into a List of Bits, follows the template for natural numbers, not the above template.
(define num->lob (lambda (n) (cond ((zero? n) null) (else (cons (remainder n 2) (num->lob (quotient n 2)))))))
Writing addone and subone for Lists of Bits is more difficult. You already know how to do it, since it's just like addition and subtraction on decimal numbers. But we need to figure out how to write functions that deal with "carrying" in addition and "borrowing" in subtraction.
(define addone (lambda (lob) (cond ((null? lob) (cons 1 null)) (else (if (zero? (first lob)) (cons 1 (rest lob)) (cons 0 (addone (rest lob))))))))
To understand this, remember that if (null? lob) is true, then we are at the front of our binary number, since our list representation is backwards. Thus, the first case simply puts the 1 we are adding at the front when we are done. Otherwise, the list of bits is not empty, and we are looking at the first bit in the list. This represents the last bit in the number that we haven't looked at yet. If this bit we are currently looking at in the list is 0, we can do our addition since 0+1=1. Otherwise, the bit is a 1, and since 1+1=10 we have to continuing carrying to the next position.
Defining subone is very similar. For convenience, we assume that if we subtract 1 from 0 (or rather its representation), we get 0 again.
(define subone (lambda (lob) (cond ((null? lob) null) (else (if (zero? (first lob)) (cons 1 (subone (rest lob))) (cons 0 (rest lob)))))))
How would you define addition of two Lists of Bits? Hint: you'll want to use addone.
How would you define multiplication? Here's two alternative hints: