Решение упражнения 2.56 из SICP
Сначала модифицируем процедуру deriv с тем, чтобы она распознавала и операцию возведения в степень:
(define (deriv exp var) (cond ((number? exp) 0) ((variable? exp) (if (same-variable? exp var) 1 0)) ((sum? exp) (make-sum (deriv (addend exp) var) (deriv (augend exp) var))) ((product? exp) (make-sum (make-product (multiplier exp) (deriv (multiplicand exp) var)) (make-product (deriv (multiplier exp) var) (multiplicand exp)))) ((exponentiation? exp) (make-product (make-product (exponent exp) (make-exponentiation (base exp) (- (exponent exp) 1))) (deriv (base exp) var))) (else (error "неизвестный тип выражения -- DERIV" exp))))
Теперь доопределим новые операции, связанные с возведением в степень. Проверка exponentiation?, а также селекторы base и exponent записываются абсолютно аналогично соответствующим процедурам для сложения и умножения:
(define (exponentiation? x) (and (pair? x) (eq? (car x) '**)))
(define (base e) (cadr e))
(define (exponent e) (caddr e))
Теперь перейдем к конструктору, в котором сразу же учтем правила сокращения. Хочу подчеркнуть, что в данный момент мы будем работать только лишь с выражениями, показатель степени которых числовой. То есть для показателя не допускается содержание выражений либо переменных. Это ограничение мы приняли еще на этапе записи процедуры deriv. В противном случае задача усложняется, так как нам нужно вводить производную для сложной функции, вводить операцию вычитания, рассматривать существенно больше случаев сокращения, оповещать об ошибках несоответствия аргументов области определения функций и т.д. - коротко говоря, последствия столь опрометчивого поступка весьма существенны. Итак, примем, что показатель является числом. Будем учитывать такие 2 правила сокращения выражений:
- x0 = 1,
- x1 = x.
Тогда получим следующее определение процедуры make-exponentiation:
(define (power a b) (exp (* b (log a))))
(define (make-exponentiation base expt) (cond ((=number? expt 0) 1) ((=number? expt 1) base) ((and (number? base) (number? expt)) (power base expt)) (else (list '** base expt))))
Проверим работу на примере:
> (deriv '(+ (** x 3) (** x 2)) 'x) (+ (* 3 (** x 2)) (* 2 x))
Ответ правильный и даже сокращен.
Comments
Comment from nobody
Date: July 10, 2008, 4:29 am
Проверка (exponentiation? exp) не является достаточной, так как только выражения типа (f(x))^n, где n — вещественное, дифференцируются по указаному правилу. Поэтому, например, попытка диференцировать (** x x) по x приводит к ошибке — попытка вычислить выражение (- ‘x 1).
Нужно или делать проверку (and (exponentiation? expr) (number? (exponent expr))), или реализовать формулу для (f(x))^g(x).
Write a comment