2014-11-09 3 views
1

Есть ли способ изменить - (минус) на + (plus) функция?change - to + in Common Lisp

Мое домашнее задание осуществить расчет грех на серии Macluaurin

sin(x) = x-(x^3/3!)+(x^5/5!) -(x^7/7!)+(x^9/9!)-... 

Каждой статью имеют разный знак. Это мой Lisp код

(defun sinMac (x series n plusminus) 
    (cond ((= series 0) 0) 
     (t (funcall plusminus 
        (/ (power x n) (factorial n)) 
        (sinMac x (- series 1) (+ n 2) plusminus))))) 

Можно ли изменить plusminus обмен подписать? если я получу '+ функция, отправьте '- на следующий рекурсивный звонок. От этого звонка (получено '-) Я звоню '+ и так далее ...

ответ

4

Вы можете сделать это с круговым списком. Как так:

(defun sin-mac (x series n plus-minus) 
    (cond ((zerop series) 0) 
     (t (funcall (car plus-minus) 
        (/ (power x n) (factorial n)) 
        (sin-mac x (1- series) (+ n 2) (cdr plus-minus)))))) 

(sin-mac x series 1 '#0=(+ - . #0#)) 

или даже лучше, завернуть начальные аргументы с помощью labels:

(defun sin-mac (x series) 
    (labels ((recur (series n plus-minus) 
      (cond ((zerop series) 0) 
        (t (funcall (car plus-minus) 
           (/ (power x n) (factorial n)) 
           (recur (1- series) (+ n 2) (cdr plus-minus))))))) 
    (recur series 1 '#0=(+ - . #0#)))) 
3

Если функция является символом, это легко:

(defun next-function (function) 
    (ecase function 
    (+ '-) 
    (- '+))) 

(defun sinMac (x series n plusminus) 
    (cond ((= series 0) 0) 
     (t (funcall plusminus 
        (/ (power x n) (factorial n)) 
        (sinMac x 
          (- series 1) 
          (+ n 2) 
          (next-function plusminus)))))) 
1

я бы не стал замените функцию, а только знак. Использование цикла для этого также кажется мне яснее (и, скорее всего, более эффективным, хотя есть еще много возможностей для оптимизации):

(defun maclaurin-sinus (x n) 
    "Calculates the sinus of x by the Maclaurin series of n elements." 
    (loop :for i :below n 
    :for sign := 1 :then (- sign) 
    :sum (let ((f (1+ (* 2 i)))) 
      (* sign 
       (/ (expt x f) 
       (factorial f)))))) 

Несколько оптимизаций сделать это примерно в 10 раз быстрее (проверено с н = 5):

(defun maclaurin-sinus-optimized (x n) 
    "Calculates the sinus of x by the Maclaurin series of n elements." 
    (declare (integer n)) 
    (loop :repeat n 
    :for j :from 0 :by 2 
    :for k :from 1 :by 2 
    :for sign := 1 :then (- sign) 
    :for e := x :then (* e x x) 
    :for f := 1 :then (* f j k) 
    :sum (/ e f sign)))