对一元三次或者四次方程,是有数学公式求精确解的,可以不用迭代法。参考了维基的上的方法,现在我贴出一元二次、三次或者四次方程的LISP求解方法。使得在求解效率可以得到极大提高。
注明: 因为这几个方程的解有可能是复数,所以我对每个解都用表的形式来列出。
如果这个表的第二项为0,那么这个解是实数,否则是复数。
譬如 :\({x^4+3x^3+7x^2+2x-5 = 0}\)
|
1 |
(Math:Quartic_Equation 1 3 7 2 -5) |
==》((-1.19281 -2.21406) (-1.19281 2.21406) (-1.24789 0) (0.633498 0))
意味着这个方程有两个实数解:-1.24789 , 0.633498
两个虚数解:-1.19281-2.21406 i ,-1.19281+2.21406i
另外在末尾附上验算测试函数。
解一元二次方程的LISP源码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
;;;============================================================= ;;;一元二次方程的解 ;;;f(x) = a*x^2+b*x+c = 0 ;;;Input: the coefficients a, b, c are real numbers ;;;Output: when a /= 0,one or Two solutions,all of them like ;;; this: (x y),means: x + y * i,if it's a real number, ;;; then y = 0.Otherwise , return a real number or nil ;;;Ref: http://en.wikipedia.org/wiki/Quadratic_equation ;;;============================================================= (defun Math:Quadratic_Equation (a b c / d e g) (if (zerop a) (if (not (zerop b)) (list (list (/ (- c) (float b)) 0)) ) (progn (setq a (float a)) (if (not (equal a 1 1e-14)) (setq b (/ b a) c (/ c a) ) ) (setq d (- (* b b) (* 4 c))) (setq e (* b -0.5)) (cond ( (equal d 0 1e-14) (list (list e 0) (list e 0)) ) ( (> d 0) (setq g (* (sqrt d) -0.5)) (list (list (- e g) 0) (list (+ e g) 0)) ) ( (< d 0) (setq g (* (sqrt (- d)) -0.5)) (list (list e (- g)) (list e g)) ) ) ) ) ) |
解一元三次方程的LISP源码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
;;;============================================================= ;;;一元三次方程的解 ;;;f(x) = a*x^3+b*x^2+c*x+d = 0 ;;;Input: the coefficients a, b, c, d are real numbers ;;;Output: when a /= 0,Three solutions,all of them like this: ;;; (x y),means: x+y*i,if it's a real number,then y = 0; ;;; otherwise goto "Math:Quadratic_Equation" ;;;Ref: http://en.wikipedia.org/wiki/Cubic_function ;;;============================================================= (defun Math:Cubic_Equation (a b c d / e f g h u w x y) (cond ( (zerop a) (Math:Quadratic_Equation b c d) ) ( (zerop d) (cons '(0 0) (Math:Quadratic_Equation a b c)) ) (t (setq b (/ b a 3.0)) (setq c (/ c a 6.0)) (setq d (/ d a 2.0)) (setq e (- (* b (- (+ c c c) (* b b))) d)) ;Alpha (setq f (- (* b b) c c)) ;Beta (setq g (- (* e e) (* f f f))) ;Delta,The nature of the roots (cond ( (equal g 0 1e-14) (setq u (MATH:CubeRoot e)) (list (list (- (+ u u) b) 0.0) (list (- (+ b u)) 0.0) (list (- (+ b u)) 0.0) ) ) ( (> g 0) (setq h (sqrt g)) (setq u (MATH:CubeRoot (+ e h))) (setq w (MATH:CubeRoot (- e h))) (setq x (- (+ b (* (+ u w) 0.5)))) (setq y (* (sqrt 3) (- u w) 0.5)) (list (list (+ u w (- b)) 0) (list x y) (list x (- y)) ) ) ( (< g 0) (setq x (/ e f (sqrt f))) (setq y (sqrt (abs (- 1 (* x x))))) (setq u (/ (atan y x) 3)) (setq w (/ (+ pi pi) 3)) (setq h (* 2 (sqrt f))) (list (list (- (* (cos u) h) b) 0) (list (- (* (cos (+ u w)) h) b) 0) (list (- (* (cos (- u w)) h) b) 0) ) ) ) ) ) ) |
解一元四次方程的解:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
;;;============================================================= ;;;一元四次方程的解 ;;;f(x) = a*x^4+b*x^3+c*x^2+d*x+e= 0 ;;;Input: the coefficients a,b,c,d,e are real numbers. ;;;Output: when a /= 0,Three solutions,all of them like this: ;;; (x y),means: x+y*i,if it's a real number,then y = 0, ;;; otherwise goto "Math:Quadratic_Equation". ;;;Ref: http://en.wikipedia.org/wiki/Quartic_function ;;;============================================================= (defun Math:Quartic_Equation (a b c d e / B2 B3 B4 EPS F G H P Q R V W X Y Z S) (setq eps 1e-8) (cond ( (equal a 0 eps) (Math:Cubic_Equation b c d e) ) ( (equal e 0 eps) (cons '(0 0) (Math:Cubic_Equation a b c d)) ) ( (and (equal b 0 eps) (equal d 0 eps)) (foreach x (Math:Quadratic_Equation a c e) (foreach y (Math:CSqrt x) (setq s (cons y s)) ) ) ) ( (setq a (float a)) (setq b (/ b a)) (setq c (/ c a)) (setq d (/ d a)) (setq e (/ e a)) (setq b2 (* b b)) (setq b3 (* b2 b)) (setq b4 (* b3 b)) (setq f (+ (* b2 -0.375) c)) ;alpha (setq g (+ (* b3 0.125) (* b c -0.5) d)) ;beta (setq h (+ (* -0.01171875 b4) (* 0.0625 c b2) (* -0.25 b d) e)) (if (equal g 0 eps) (progn (setq x (* b -0.25)) (mapcar (function (lambda (e) (list (+ (car e) x) (cadr e)))) (Math:Quartic_Equation 1 0 f 0 h) ;Recursion ) ) (progn (setq p (- (* f f 2) h)) (setq q (- (* f f f 0.5) (* f h 0.5) (* g g 0.125))) (setq r (Math:Cubic_Equation 1 (* 2.5 f) p q)) (while (not (equal (cadar r) 0 eps)) (setq r (cdr r)) ) (setq r (caar r)) (setq w (sqrt (abs (+ f r r)))) (foreach i (list + -) (foreach j (list + -) (setq x (i (* b -0.25) (* w 0.5))) (setq y (- (+ f f f r r (i (/ g 0.5 w))))) (if (< y 0) (setq z (list x (j (* (sqrt (- y)) 0.5)))) (setq z (list (+ x (j (* (sqrt y) 0.5))) 0)) ) (setq S (cons z S)) ) ) ) ) ) ) ) |
复数相关代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
;;;============================================================= ;;;立方根(为解三次和四次方程编写,因expt函数第一个参数不能为负) ;;;输入:x 实数 ;;;输出:x 的立方根 ;;;============================================================= (defun MATH:CubeRoot (x) (if (< x 0) (- (expt (- x) 0.33333333333333333333333)) (expt x 0.33333333333333333333333) ) ) ;;;============================================================= ;;;复数加复数 ;;;输入:Z1--复数,Z2--复数 ;;;输出:复数跟实数相加的结果 ;;;============================================================= (defun Math:C+C (z1 z2) (mapcar '+ z1 z2) ) ;;;============================================================= ;;;复数减复数 ;;;输入:Z1--复数,Z2--复数 ;;;输出:复数跟实数相减的结果 ;;;============================================================= (defun math:C-C (z1 z2) (mapcar '- Z1 Z2) ) ;;;============================================================= ;;;复数乘复数 ;;;输入:Z1--复数,Z2--复数 ;;;输出:复数跟实数相乘的结果 ;;;============================================================= (defun Math:C*C (Z1 Z2) (list (- (* (car Z1) (car z2)) (* (cadr z1) (cadr z2))) (+ (* (car Z1) (cadr Z2)) (* (cadr z1) (car Z2))) ) ) ;;;============================================================= ;;;复数除以复数 ;;;输入:Z1--复数,Z2--复数 ;;;输出:复数跟实数相除的结果 ;;;============================================================= (defun Math:C/C (Z1 Z2 / a b c d N) (setq a (car z1)) (setq b (cadr z1)) (setq c (car z2)) (setq d (cadr z2)) (setq N (float (+ (* c c) (* d d)))) (if (not (zerop N)) (list (/ (+ (* a c) (* b d)) N) (/ (- (* b c) (* a d)) N) ) ) ) ;;;============================================================= ;;;复数加实数 ;;;输入:Z --复数,R --实数 ;;;输出:复数跟实数相加的结果 ;;;============================================================= (defun Math:C+R (Z R) (list (+ (car z) R) (cadr z)) ) ;;;============================================================= ;;;复数减实数 ;;;输入:Z --复数,R --实数 ;;;输出:复数跟实数相减的结果 ;;;============================================================= (defun Math:C-R (Z R) (list (- (car z) R) (cadr z)) ) ;;;============================================================= ;;;复数乘实数 ;;;输入:Z --复数,R --实数 ;;;输出:复数跟实数相乘的结果 ;;;============================================================= (defun Math:C*R (Z R) (list (* (car z) R) (* (cadr z) R)) ) ;;;============================================================= ;;;复数除以实数 ;;;输入:Z --复数,R --实数 ;;;输出:复数跟实数相除的结果 ;;;============================================================= (defun Math:C/R (Z R) (if (not (zerop R)) (list (/ (car z) R) (/ (cadr z) R)) ) ) ;;;============================================================= ;;;复数的模 ;;;输入:Z --复数 ;;;输出:复数的模,即复数代表的矢量长度 ;;;============================================================= (defun MATH:CNormal (Z) (distance '(0 0) Z) ) ;;;============================================================= ;;;复数的平方根 ;;;输入:Z --复数 ;;;输出:复数的平方根,以复数形式表达,有两个解 ;;;============================================================= (defun Math:CSqrt (Z / x y a r) (setq x (car z)) (setq y (cadr z)) (if (equal y 0 1e-14) (if (> x 0) (list (list (setq x (sqrt x)) 0) (list (- x) 0)) (list (list 0 (setq y (sqrt (- x)))) (list 0 (- y))) ) (progn (setq a (* (atan y x) 0.5)) (setq r (sqrt (distance '(0 0) Z))) (setq x (* r (cos a))) (setq y (* r (sin a))) (list (list x y) (list (- x) (- y))) ) ) ) ;;;============================================================= ;;;复数的方根 ;;;输入:Z --复数, n --正整数 ;;;输出:复数的n次方根,以复数形式表达,有n个解。 ;;;============================================================= (defun MATH:CRoot (Z n / r a b i s 2Pi) (if (and (= (type n) 'INT) (> n 0)) (progn (setq r (expt (distance '(0 0) z) (/ 1. n))) (setq a (atan (cadr z) (car z))) (setq i 0) (setq 2Pi (+ pi pi)) (repeat n (setq b (/ (+ a (* i 2Pi)) n)) (setq s (cons (list (* r (cos b)) (* r (sin b))) s)) (setq i (1+ i)) ) (reverse s) ) ) ) ;;;============================================================= ;;;复数的实幂指数 ;;;输入:Z --复数, x -- 实数 ;;;输出:复数Z 的x次幂,以复数形式表达。 ;;;============================================================= (defun MATH:CRPower (Z x / a r) (setq a (atan (cadr Z) (car Z))) (setq r (expt (distance '(0 0) Z) x)) (list (* r (cos (* a x))) (* r (sin (* a x)))) ) ;;;============================================================= ;;;复数的复幂指数 ;;;输入:Z1 --复数, Z2 -- 复数 ;;;输出:复数Z1的Z2次幂,以复数形式表达。 ;;;============================================================= (defun MATH:CZPower (Z1 Z2 / a r x y k) (if (> (setq r (distance '(0 0) Z1)) 1e-20) (progn (setq a (atan (cadr Z1) (car Z1))) (setq x (car z2)) (setq y (cadr z2)) (setq k (log r)) (setq r (exp (- (* k x) (* y a)))) (setq a (+ (* k y) (* x a))) (list (* r (cos a)) (* r (sin a))) ) ) ) ;;;============================================================= ;;;复数的自然对数 ;;;输入:Z --复数 ;;;输出:复数Z 的自然对数,以复数形式表达。 ;;;============================================================= (defun MATH:CExp (Z / r) (if (> (setq r (distance '(0 0) Z)) 1e-20) (list (log r) (atan (cadr Z) (car Z))) ) ) ;;;============================================================= ;;;复数的余弦 ;;;输入:Z --复数 ;;;输出:复数Z 的余弦,以复数形式表达。 ;;;============================================================= (defun MATH:CCOS (Z / x y c s u v) (setq x (car z)) (setq y (cadr z)) (if (equal y 0 1e-20) (list (cos x) 0) (progn (setq c (* 0.5 (cos x))) (setq s (* 0.5 (sin x))) (setq u (exp y)) (setq v (exp (- y))) (list (* c (+ v u)) (* s (- v u))) ) ) ) ;;;============================================================= ;;;复数的正弦 ;;;输入:Z --复数 ;;;输出:复数Z 的正弦,以复数形式表达。 ;;;============================================================= (defun MATH:CSIN (Z / x y c s u v) (setq x (car z)) (setq y (cadr z)) (if (equal y 0 1e-20) (list (sin x) 0) (progn (setq s (* 0.5 (sin x))) (setq c (* 0.5 (cos x))) (setq u (exp (- y))) (setq v (exp y)) (list (* s (+ v u)) (* c (- v u))) ) ) ) ;;;============================================================= ;;;复数的正切 ;;;输入:Z --复数 ;;;输出:复数Z 的正切,以复数形式表达。 ;;;============================================================= (defun MATH:CTAN (Z / x y c s u v) (MATH:C/C (MATH:CSIN Z) (MATH:CCOS Z)) ) ;;;============================================================= ;;;实系数的复数多项式运算 ;;;输入:Z --复数, RealNumbers --实系数列表 ;;;输出:根据实系数多项式复数方程值,用复数表示。 ;;;============================================================= (defun MATH:CReal_Polynomial (Z RealNumbers / f) (cond ( (cdr RealNumbers) (setq f (MATH:C*R Z (car RealNumbers))) (repeat (- (length RealNumbers) 2) (setq RealNumbers (cdr RealNumbers)) (setq f (MATH:C+R f (car RealNumbers))) (setq f (MATH:C*C f Z)) ) (setq f (MATH:C+R f (cadr RealNumbers))) ) ( (car RealNumbers) (list (car RealNumbers) 0)) ) ) ;;;============================================================= ;;;虚系数的复数多项式运算 ;;;输入:Z --复数, ImaginaryNumbers--复系数列表 ;;;输出:根据复系数多项式复数方程值,用复数表示。 ;;;============================================================= (defun MATH:CImaginary_Polynomial (Z ImaginaryNumbers / f) (if (setq f (car ImaginaryNumbers)) (progn (repeat (1- (length ImaginaryNumbers)) (setq ImaginaryNumbers (cdr ImaginaryNumbers)) (setq f (MATH:C*C f Z)) (setq f (MATH:C+C f (car ImaginaryNumbers))) ) f ) ) ) |
测试代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
;;;============================================================= ;;;以下程序为测试用: ;;;Test for "Math:Quartic_Equation" ;;;If the difference between the Coefficients is big,it will get ;;;some float point error. ;;;============================================================= (defun C:t4 (/ a b c d e S z z1 z2 z3 z4) (initget 1) (setq a (getreal "\nCoefficient a:")) (initget 1) (setq b (getreal "\nCoefficient b:")) (initget 1) (setq c (getreal "\nCoefficient c:")) (initget 1) (setq d (getreal "\nCoefficient d:")) (initget 1) (setq e (getreal "\nCoefficient e:")) ;(MISC:test 1000 '((Math:Quartic_Equation a b c d e))) (setq S (Math:Quartic_Equation a b c d e)) ;get the solutions (foreach z S (princ "\n") (princ (mapcar '(lambda (x) (rtos x 2 20)) z)) ;print them. ) (foreach z S ;Check every solution (setq f (MATH:CReal_Polynomial z (list a b c d e))) (if (not (equal f '(0 0) 1e-6)) ;if f(z) /= 0.0,maybe it's caused by floating point operation; (alert (strcat "Maybe it's a Wrong solution: f(" (vl-princ-to-string z) ") = " (VL-PRINC-TO-STRING f) ) ) ) ) (princ) ) (defun C:t3 (/ a b c d e S z z1 z2 z3 z4) (initget 1) (setq a (getreal "\nCoefficient a:")) (initget 1) (setq b (getreal "\nCoefficient b:")) (initget 1) (setq c (getreal "\nCoefficient c:")) (initget 1) (setq d (getreal "\nCoefficient d:")) (UTI:BENCH 20000 (list (list 'Math:Cubic_Equation a b c d) (list 'Math:Cubic_Equation1 a b c d) ) ) (foreach n '(Math:Cubic_Equation Math:Cubic_Equation1) (setq S (apply n (list a b c d))) ;get the solutions (foreach z S (princ "\n") (princ (mapcar '(lambda (x) (rtos x 2 20)) z)) ;print them. ) (foreach z S ;Check every solution (setq f (MATH:CReal_Polynomial z (list a b c d))) (if (not (equal f '(0 0) 1e-6)) ;if f(z) /= 0.0,maybe it's caused by floating point operation; (alert (strcat "Use " (VL-PRINC-TO-STRING n) ",Maybe it's a Wrong solution: f(" (vl-princ-to-string z) ") = " (VL-PRINC-TO-STRING f) ) ) ) ) ) (princ) ) (princ "\nThe command is : test.") (vl-load-com) (princ) |