#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound int) (car int))
(define (upper-bound int) (cdr int))

(define (mul-interval-new x y)
  (define (bin bool) (if bool 1 0))
  (let ((xl (lower-bound x)) (xu (upper-bound x))
        (yl (lower-bound y)) (yu (upper-bound y)))
    (let ((switch 
            (+ (* 8 (bin (>= xl 0)))
               (* 4 (bin (>= xu 0)))
               (* 2 (bin (>= yl 0)))
               (bin (>= yu 0)))))
      (cond ((= switch 15) (make-interval (* xl yl) (* xu yu)))
            ((= switch 13) (make-interval (* xu yl) (* xu yu)))
            ((= switch 12) (make-interval (* xu yl) (* xl yu)))
            ((= switch 7)  (make-interval (* xl yu) (* xu yu)))
            ((= switch 4)  (make-interval (* xu yl) (* xl yl)))
            ((= switch 3)  (make-interval (* xl yu) (* xu yl)))
            ((= switch 1)  (make-interval (* xl yu) (* xl yl)))
            ((= switch 0)  (make-interval (* xu yu) (* xl yl)))
        ;; special comparison case
            ((= switch 5)  (make-interval (min (* xl yu) (* xu yl))
                                          (max (* xl yl) (* xu yu))))
            (else (error "invalid interval"))))))

(define (mul-interval x y)
  (let ((p1 (* (lower-bound x) (lower-bound y))) 
        (p2 (* (lower-bound x) (upper-bound y)))
        (p3 (* (upper-bound x) (lower-bound y))) 
        (p4 (* (upper-bound x) (upper-bound y))))
    (make-interval (min p1 p2 p3 p4) (max p1 p2 p3 p4))))

;;Testing code
(define (myrandom lower upper nsteps)
  (+ lower (* (- upper lower) (/ (random nsteps) nsteps))))
(define (random-interval)
  (let ((a (myrandom -10 10 10000)) (b (myrandom -10 10 10000)))
    (if (< a b) (make-interval a b) (random-interval))))
(define (interval-equal? int1 int2)
  (and (= (lower-bound int1) (lower-bound int2))
       (= (upper-bound int1) (upper-bound int2))))
(define (test-mul-interval n)
  (if (= n 0) #t
    (let ((x (random-interval)) (y (random-interval)))
      (if (interval-equal? (mul-interval x y) (mul-interval-new x y))
        (test-mul-interval (- n 1))
        #f))))
(display "Testing new code for 10000 cases. All intervals equal?")
(newline)
(display (if (test-mul-interval 10000) "true" "false"))
