Решение упражнения 2.56 из SICP

8 February, 2008 (21:33) | Решения упражнений

Сначала модифицируем процедуру 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 правила сокращения выражений:

  1. x0 = 1,
  2. 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