Решение упражнения 2.11 из SICP
Это упражнение простое, но требует внимания. Девять случаев, о которых сказано в условии, получаются путем комбинации трех вариантов расположения первого интервала относительно нуля с тремя вариантами расположения второго интервала относительно нуля.
Три возможных варианта следующие:
- интервал лежит целиком справа от нуля (обе границы неотрицательны);
- интервал лежит целиком слева от нуля (обе границы неположительны);
- интервал содержит нуль (левая граница отрицательна, а правая - положительна).
Рассматривая каждый из этих случаев, легко увидеть, что во всех ситуациях, кроме единственной (когда оба интервала-сомножителя содержат нуль), мы сразу же можем сказать, какие границы исходных интервалов необходимо перемножить для получения границ интервала-произведения. Лишь в случае, когда оба перемножаемых интервала содержат нуль, нам требуется выбрать максимум и минимум из двух произведений для каждой границы (даже в этом случае есть экономия, так как в исходной версии произведения минимум и максимум выбирался из четырех вариантов, а не двух).
Вот код процедуры, реализующей оптимизационное предложение Бена:
(define (mul-interval x y) (let ((xl (lower-bound x)) (xu (upper-bound x)) (yl (lower-bound y)) (yu (upper-bound y))) (cond ((>= xl 0) (cond ((>= yl 0) (make-interval (* xl yl) (* xu yu))) ((<= yu 0) (make-interval (* xu yl) (* xl yu))) (else (make-interval (* xu yl) (* xu yu))))) ((<= xu 0) (cond ((>= yl 0) (make-interval (* xl yu) (* xu yl))) ((<= yu 0) (make-interval (* xu yu) (* xl yl))) (else (make-interval (* xl yu) (* xl yl))))) (else (cond ((>= yl 0) (make-interval (* xl yu) (* xu yu))) ((<= yu 0) (make-interval (* xu yl) (* xl yl))) (else (make-interval (min (* xl yu) (* xu yl)) (max (* xl yl) (* xu yu)))))))))
Не исключаю, что его можно записать компактнее.
Comments
Comment from Dima
Date: June 22, 2008, 3:30 pm
Не знаю если это компактнее, но можно записать протседуру так, что “вручную” необходимо рассмотреть только 6 вариантов вместо 9ти. Это возможно благодаря коммутативности умножения.
(define (mul-interval x y)
(let ((xl (lower-bound x))
(xu (upper-bound x))
(yl (lower-bound y))
(yu (upper-bound y)))
(cond ((>= xl 0)
(cond ((>= yl 0)
(make-interval (* xl yl) (* xu yu)))
((<= yu 0)
(make-interval (* xu yl) (* xl yu)))
(else
(make-interval (* xu yl) (* xu yu)))))
((and (<= xu 0) ( xu 0) (< xl 0))
(cond (( yu 0) (< yl 0))
(make-interval (min (* xl yu) (* xu yl))
(max (* xl yl) (* xu yu))))))
(else (mul-interval y x)))))
Comment from Dima
Date: June 23, 2008, 11:19 am
Всё что было в угловых скобках, в (>= …) и так далее, было стёрто. Попробую ещё раз. Заменяю на less= и less.
(define (mul-interval x y)
(let ((xl (lower-bound x))
(xu (upper-bound x))
(yl (lower-bound y))
(yu (upper-bound y)))
(cond ((>= xl 0)
(cond ((>= yl 0)
(make-interval (* xl yl) (* xu yu)))
((less= yu 0)
(make-interval (* xu yl) (* xl yu)))
(else
(make-interval (* xu yl) (* xu yu)))))
((and (less= xu 0) (less= yu 0))
(make-interval (* xu yu) (* xl yl)))
((and (> xu 0) (less xl 0))
(cond ((less= yu 0)
(make-interval (* xu yl) (* xl yl)))
((and (> yu 0) (less yl 0))
(make-interval (min (* xl yu) (* xu yl))
(max (* xl yl) (* xu yu))))))
(else (mul-interval y x)))))
Write a comment