Annotation of freem/mlib/%ulmath.m, revision 1.1.1.1
1.1 snw 1: %ulmath ; MATH library - version 0.5.0.1
2: ;
3: ; Unless otherwise noted, the code below
4: ; was approved in document X11/95-11
5: ;
6: ; CORRECTION INFORMATION
7: ; Due to the overall routine size this has not been provided
8: ; It is available from Ed de Moel who provided these functions
9: ;
10: ABS(X) Quit $Translate(+X,"-")
11: ;===
12: ;
13: ;
14: %ARCCOS(X) ;
15: ;
16: New A,N,R,SIGN,XX
17: If X<-1 Set $Ecode=",M28,"
18: If X>1 Set $Ecode=",M28,"
19: Set SIGN=1 Set:X<0 X=-X,SIGN=-1
20: Set A(0)=1.5707963050,A(1)=-0.2145988016,A(2)=0.0889789874
21: Set A(3)=-0.0501743046,A(4)=0.0308918810,A(5)=-0.0170881256
22: Set A(6)=0.0066700901,A(7)=-0.0012624911
23: Set R=A(0),XX=1 For N=1:1:7 Set XX=XX*X,R=A(N)*XX+R
24: ;
25: Set R=$$SQRT(1-X,11)*R
26: ;;;
27: ;
28: Quit R*SIGN
29: ;===
30: ;
31: ;
32: ARCCOS(X,PREC) ;
33: I '$D(PREC) Q $$%ARCCOS(X)
34: ;
35: New L,LIM,K,SIG,SIGS,VALUE
36: ;;;
37: ;
38: If X<-1 Set $Ecode=",M28,"
39: If X>1 Set $Ecode=",M28,"
40: Set PREC=$Get(PREC,11)
41: ;
42: If $Translate(X,"-")=1 Quit 0
43: ;;;
44: ;
45: Set SIG=$Select(X<0:-1,1:1),VALUE=1-(X*X)
46: ;
47: Set X=$$SQRT(VALUE,PREC)
48: ;;;
49: ;
50: If $Translate(X,"-")=1 Do Quit VALUE
51: . ;;;
52: . ;
53: . Set VALUE=$$PI()/2*X
54: . Quit
55: ;
56: If X>0.9 Do Quit VALUE
57: . ;;;
58: . ;
59: . Set SIGS=$Select(X<0:-1,1:1)
60: . Set VALUE=1/(1/X/X-1)
61: . ;
62: . Set X=$$SQRT(VALUE,PREC)
63: . ;;;
64: . ;
65: . ;
66: . Set VALUE=$$ARCTAN(X,PREC)*SIGS
67: . ;;;
68: ;
69: . Quit
70: Set (VALUE,L)=X
71: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
72: For K=3:2 Do Quit:($Translate(L,"-")<LIM)
73: . Set L=L*X*X*(K-2)/(K-1)*(K-2)/K,VALUE=VALUE+L
74: . Quit
75: Quit $Select(SIG<0:$$PI()-VALUE,1:VALUE)
76: ;===
77: ;
78: ;
79: ARCCOSH(X,PREC) ;
80: If X<1 Set $Ecode=",M28,"
81: New SQ
82: ;
83: Set PREC=$Get(PREC,11)
84: ;;;
85: ;
86: Set SQ=$$SQRT(X*X-1,PREC)
87: Quit $$LOG(X+SQ,PREC)
88: ;===
89: ;
90: ;
91: ARCCOT(X,PREC) ;
92: Set PREC=$Get(PREC,11)
93: Set X=1/X
94: Quit $$ARCTAN(X,PREC)
95: ;===
96: ;
97: ;
98: ARCCOTH(X,PREC) ;
99: New L1,L2
100: ;
101: Set PREC=$Get(PREC,11)
102: ;;;
103: ;
104: Set L1=$$LOG(X+1,PREC)
105: Set L2=$$LOG(X-1,PREC)
106: Quit L1-L2/2
107: ;===
108: ;
109: ;
110: ARCCSC(X,PREC) ;
111: Set PREC=$Get(PREC,11)
112: Set X=1/X
113: Quit $$ARCSIN(X,PREC)
114: ;===
115: ;
116: ;
117: ARCSEC(X,PREC) ;
118: Set PREC=$Get(PREC,11)
119: Set X=1/X
120: Quit $$ARCCOS(X,PREC)
121: ;===
122: ;
123: ;
124: %ARCSIN(X) ;
125: ;;; ; Number ~~
126: ; Winfried Gerum (8 June 1995)
127: ;
128: New A,N,R,SIGN,XX
129: If X<-1 Set $Ecode=",M28,"
130: If X>1 Set $Ecode=",M28,"
131: Set SIGN=1 Set:X<0 X=-X,SIGN=-1
132: Set A(0)=1.5707963050,A(1)=-0.2145988016,A(2)=0.0889789874
133: Set A(3)=-0.0501743046,A(4)=0.0308918810,A(5)=-0.0170881256
134: Set A(6)=0.0066700901,A(7)=-0.0012624911
135: Set R=A(0),XX=1 For N=1:1:7 Set XX=XX*X,R=A(N)*XX+R
136: ;
137: Set R=$$SQRT(1-X,11)*R
138: ;;;
139: ;
140: Set R=$$PI()/2-R
141: Quit R*SIGN
142: ;===
143: ;
144: ;
145: ARCSIN(X,PREC) ;
146: I '$D(PREC) Q $$%ARCSIN(X)
147: New L,LIM,K,SIGS,VALUE
148: Set PREC=$Get(PREC,11)
149: ;
150: If $Translate(X,"-")=1 Do Quit VALUE
151: . ;;;
152: . ;
153: . Set VALUE=$$PI()/2*X
154: . Quit
155: ;
156: If X>0.99999 Do Quit VALUE
157: . ;;;
158: . ;
159: . Set SIGS=$Select(X<0:-1,1:1)
160: . Set VALUE=1/(1/X/X-1)
161: . ;
162: . ;;;
163: . ;
164: . Set VALUE=$$ARCTAN(X,PREC)*SIGS
165: . ;;;
166: . ;
167: . Quit
168: Set (VALUE,L)=X
169: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
170: For K=3:2 Do Quit:($Translate(L,"-")<LIM)
171: . Set L=L*X*X*(K-2)/(K-1)*(K-2)/K,VALUE=VALUE+L
172: . Quit
173: Quit VALUE
174: ;===
175: ;
176: ;
177: ARCSINH(X,PREC) ;
178: If X<1 Set $Ecode=",M28,"
179: New SQ
180: ;
181: Set PREC=$Get(PREC,11)
182: ;;;
183: ;
184: Set SQ=$$SQRT(X*X+1,PREC)
185: Quit $$LOG(X+SQ,PREC)
186: ;===
187: ;
188: ;
189: ARCTAN(X,PREC) ;
190: New FOLD,HI,L,LIM,LO,K,SIGN,SIGS,SIGT,VALUE
191: Set PREC=$Get(PREC,11)
192: Set LO=0.0000000001,HI=9999999999
193: Set SIGT=$Select(X<0:-1,1:1),X=$Translate(X,"-")
194: Set X=$Select(X<LO:LO,X>HI:HI,1:X)
195: ;
196: Set FOLD=$Select(X'<1:0,1:1)
197: ;;;
198: ;
199: Set X=$Select(FOLD:1/X,1:X)
200: Set L=X,VALUE=$$PI()/2-(1/X),SIGN=1
201: ;
202: If X<1.3 Do Quit VALUE
203: . ;;;
204: . ;
205: . Set X=$Select(FOLD:1/X,1:X),VALUE=1/((1/X/X)+1)
206: . ;
207: . Set X=$$SQRT(VALUE,PREC)
208: . ;;;
209: . ;
210: . If $Translate(X,"-")=1 Do Quit
211: . . Set VALUE=$$PI()/2*X
212: . . Quit
213: . If X>0.9 Do Quit
214: . . Set SIGS=$Select(X<0:-1,1:1)
215: . . Set VALUE=1/(1/X/X-1)
216: . . Set X=$$SQRT(VALUE)
217: . . Set VALUE=$$ARCTAN(X,10)
218: . . Set VALUE=VALUE*SIGS
219: . . Quit
220: . Set (VALUE,L)=X
221: . Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
222: . For K=3:2 Do Quit:($Translate(L,"-")<LIM)
223: . . Set L=L*X*X*(K-2)/(K-1)*(K-2)/K,VALUE=VALUE+L
224: . . Quit
225: . Set VALUE=$Select(SIGT<1:-VALUE,1:VALUE)
226: . Quit
227: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
228: For K=3:2 Do Quit:($Translate(1/L,"-")<LIM)
229: . ;
230: . Set L=L*X*X,VALUE=VALUE+(1/(K*L)*SIGN)
231: . ;;;
232: . ;
233: . Set SIGN=SIGN*-1
234: . Quit
235: Set VALUE=$Select(FOLD:$$PI()/2-VALUE,1:VALUE)
236: Set VALUE=$Select(SIGT<1:-VALUE,1:VALUE)
237: Quit VALUE
238: ;===
239: ;
240: ;
241: ARCTANH(X,PREC) ;
242: If X<-1 Set $Ecode=",M28,"
243: If X>1 Set $Ecode=",M28,"
244: ;
245: Set PREC=$Get(PREC,11)
246: ;;;
247: ;
248: Quit $$LOG(1+X/(1-X),PREC)/2
249: ;===
250: ;
251: ;
252: CABS(Z) ;
253: New ZRE,ZIM
254: Set ZRE=+Z,ZIM=+$Piece(Z,"%",2)
255: Quit $$SQRT(ZRE*ZRE+(ZIM*ZIM))
256: ;===
257: ;
258: ;
259: CADD(X,Y) ;
260: New XRE,XIM,YRE,YIM
261: Set XRE=+X,XIM=+$Piece(X,"%",2)
262: Set YRE=+Y,YIM=+$Piece(Y,"%",2)
263: Quit XRE+YRE_"%"_(XIM+YIM)
264: ;===
265: ;
266: ;
267: CCOS(Z,PREC) ;
268: New E1,E2,IA
269: ;
270: Set PREC=$Get(PREC,11)
271: ;;;
272: ;
273: Set IA=$$CMUL(Z,"0%1")
274: Set E1=$$CEXP(IA,PREC)
275: Set IA=-IA_"%"_(-$Piece(IA,"%",2))
276: Set E2=$$CEXP(IA,PREC)
277: Set IA=$$CADD(E1,E2)
278: Quit $$CMUL(IA,"0.5%0")
279: ;===
280: ;
281: ;
282: CDIV(X,Y) ;
283: New D,IM,RE,XIM,XRE,YIM,YRE
284: Set XRE=+X,XIM=+$Piece(X,"%",2)
285: Set YRE=+Y,YIM=+$Piece(Y,"%",2)
286: Set D=YRE*YRE+(YIM*YIM)
287: Set RE=XRE*YRE+(XIM*YIM)/D
288: Set IM=XIM*YRE-(XRE*YIM)/D
289: Quit RE_"%"_IM
290: ;===
291: ;
292: ;
293: CEXP(Z,PREC) ;
294: New R,ZIM,ZRE
295: ;
296: Set PREC=$Get(PREC,11)
297: ;;;
298: ;
299: Set ZRE=+Z,ZIM=+$Piece(Z,"%",2)
300: Set R=$$EXP(ZRE,PREC)
301: Quit R*$$COS(ZIM,PREC)_"%"_(R*$$SIN(ZIM,PREC))
302: ;===
303: ;
304: ;
305: CLOG(Z,PREC) ;
306: New ABS,ARG,ZIM,ZRE
307: ;
308: Set PREC=$Get(PREC,11)
309: ;;;
310: ;
311: Set ABS=$$CABS(Z)
312: Set ZRE=+Z,ZIM=+$Piece(Z,"%",2)
313: ;
314: Set ARG=$$ARCTAN(ZIM/ZRE,PREC)
315: ;;;
316: ;
317: Quit $$LOG(ABS,PREC)_"%"_ARG
318: ;===
319: ;
320: ;
321: CMUL(X,Y) ;
322: New XIM,XRE,YIM,YRE
323: Set XRE=+X,XIM=+$Piece(X,"%",2)
324: Set YRE=+Y,YIM=+$Piece(Y,"%",2)
325: Quit XRE*YRE-(XIM*YIM)_"%"_(XRE*YIM+(XIM*YRE))
326: ;===
327: ;
328: ;
329: COMPLEX(X) Quit +X_"%0"
330: ;===
331: ;
332: ;
333: CONJUG(Z) ;
334: New ZIM,ZRE
335: Set ZRE=+Z,ZIM=+$Piece(Z,"%",2)
336: Quit ZRE_"%"_(-ZIM)
337: ;===
338: ;
339: ;
340: COS(X,PREC) ;
341: I '$D(PREC) Q $$%COS(X)
342: New L,LIM,K,SIGN,VALUE
343: ;
344: Set:X[":" X=$$DMSDEC(X)
345: ;;;
346: ;
347: Set PREC=$Get(PREC,11)
348: Set X=X#(2*$$PI())
349: Set (VALUE,L)=1,SIGN=-1
350: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
351: For K=2:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
352: . Set L=L*X*X/(K-1*K),VALUE=VALUE+(SIGN*L)
353: . Quit
354: Quit VALUE
355: ;===
356: ;
357: ;
358: %COS(X) ;
359: ;;; ; Number ~~
360: ; Winfried Gerum (8 June 1995)
361: ;
362: New A,N,PI,R,SIGN,XX
363: ;
364: ; This approximation only works for 0 <= x <= pi/2
365: ; so reduce angle to correct quadrant.
366: ;
367: Set PI=$$PI(),X=X#(PI*2),SIGN=1
368: Set:X>PI X=2*PI-X
369: Set:X*2>PI X=PI-X,SIGN=-1
370: ;
371: Set XX=X*X,A(1)=-0.4999999963,A(2)=0.0416666418
372: Set A(3)=-0.0013888397,A(4)=0.0000247609,A(5)=-0.0000002605
373: Set (X,R)=1 For N=1:1:5 Set X=X*XX,R=A(N)*X+R
374: Quit R*SIGN
375: ;===
376: ;
377: ;
378: COSH(X,PREC) ;
379: ;
380: New E,F,I,P,R,T,XX
381: ;;;
382: ;
383: Set PREC=$Get(PREC,11)+1
384: Set @("E=1E-"_PREC)
385: Set XX=X*X,F=1,(P,R,T)=1,I=1
386: For Set T=T*XX,F=I+1*I*F,R=T/F+R,P=P-R/R,I=I+2 If -E<P,P<E Quit
387: Quit R
388: ;===
389: ;
390: ;
391: COT(X,PREC) ;
392: New C,L,LIM,K,SIGN,VALUE
393: Set:X[":" X=$$DMSDEC(X)
394: ;;;
395: ;
396: Set PREC=$Get(PREC,11)
397: Set (VALUE,L)=1,SIGN=-1
398: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
399: For K=2:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
400: . Set L=L*X*X/(K-1*K),VALUE=VALUE+(SIGN*L)
401: . Quit
402: Set C=VALUE
403: Set X=X#(2*$$PI())
404: Set (VALUE,L)=X,SIGN=-1
405: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
406: For K=3:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
407: . Set L=L/(K-1)*X/K*X,VALUE=VALUE+(SIGN*L)
408: . Quit
409: If 'VALUE Quit "INFINITE"
410: Quit VALUE=C/VALUE
411: ;===
412: ;
413: ;
414: COTH(X,PREC) ;
415: New SINH
416: If 'X Quit "INFINITE"
417: ;
418: Set PREC=$Get(PREC,11)
419: ;;;
420: ;
421: Set SINH=$$SINH(X,PREC)
422: If 'SINH Quit "INFINITE"
423: Quit $$COSH(X,PREC)/SINH
424: ;===
425: ;
426: ;
427: CPOWER(Z,N,PREC) ;
428: New AR,NIM,NRE,PHI,PI,R,RHO,TH,ZIM,ZRE
429: ;
430: Set PREC=$Get(PREC,11)
431: ;;;
432: ;
433: Set ZRE=+Z,ZIM=+$Piece(Z,"%",2)
434: Set NRE=+N,NIM=+$Piece(N,"%",2)
435: If 'ZRE,'ZIM,'NRE,'NIM Set $Ecode=",M28,"
436: ;
437: If 'ZRE,'ZIM Quit "0%0"
438: ;;;
439: ;
440: Set PI=$$PI()
441: ;
442: Set R=$$SQRT(ZRE*ZRE+(ZIM*ZIM),PREC)
443: ;;;
444: ;
445: ;
446: If ZRE Set TH=$$ARCTAN(ZIM/ZRE,PREC)
447: ;;;
448: ;
449: Else Set TH=$SELECT(ZIM>0:PI/2,1:-PI/2)
450: ;;;
451: ;
452: Set RHO=$$LOG(R,PREC)
453: Set AR=$$EXP(RHO*NRE-(TH*NIM),PREC)
454: Set PHI=RHO*NIM+(NRE*TH)
455: Quit AR*$$COS(PHI,PREC)_"%"_(AR*$$SIN(PHI,PREC))
456: ;===
457: ;
458: ;
459: CSC(X,PREC) ;
460: New L,LIM,K,SIGN,VALUE
461: ;
462: ; Winfried Gerum (8 June 1995)
463: Set:X[":" X=$$DMSDEC(X)
464: ;;;
465: ;
466: Set PREC=$Get(PREC,11)
467: ;;;
468: ;
469: Set X=X#(2*$$PI())
470: Set (VALUE,L)=X,SIGN=-1
471: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
472: For K=3:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
473: . Set L=L/(K-1)*X/K*X,VALUE=VALUE+(SIGN*L)
474: . Quit
475: If 'VALUE Quit "INFINITE"
476: Quit 1/VALUE
477: ;===
478: ;
479: ;
480: ;
481: CSCH(X,PREC)
482: Quit 1/$$SINH(X,$Get(PREC,11))
483: ;;;
484: ;
485: ;===
486: ;
487: ;
488: CSIN(Z,PREC) ;
489: New IA,E1,E2
490: ;
491: Set PREC=$Get(PREC,11)
492: ;;;
493: ;
494: Set IA=$$CMUL(Z,"0%1")
495: Set E1=$$CEXP(IA,PREC)
496: Set IA=-IA_"%"_(-$Piece(IA,"%",2))
497: Set E2=$$CEXP(IA,PREC)
498: Set IA=$$CSUB(E1,E2)
499: Set IA=$$CMUL(IA,"0.5%0")
500: Quit $$CMUL("0%-1",IA)
501: ;===
502: ;
503: ;
504: CSUB(X,Y) ;
505: New XIM,XRE,YIM,YRE
506: Set XRE=+X,XIM=+$Piece(X,"%",2)
507: Set YRE=+Y,YIM=+$Piece(Y,"%",2)
508: Quit XRE-YRE_"%"_(XIM-YIM)
509: ;===
510: ;
511: ;
512: DECDMS(X,PREC) ;
513: Set PREC=$Get(PREC,5)
514: Set X=X#360*3600
515: Set X=+$Justify(X,0,$Select((PREC-$Length(X\1))'<0:PREC-$Length(X\1),1:0))
516: Quit X\3600_":"_(X\60#60)_":"_(X#60)
517: ;===
518: ;
519: ;
520: DEGRAD(X) Quit X*3.14159265358979/180
521: ;===
522: ;
523: ;
524: DMSDEC(X) ;
525: Quit $Piece(X,":")+($Piece(X,":",2)/60)+($Piece(X,":",3)/3600)
526: ;===
527: ;
528: ;
529: E() Quit 2.71828182845905
530: ;===
531: ;
532: ;
533: EXP(X,PREC) ;
534: New L,LIM,K,VALUE
535: Set PREC=$Get(PREC,11)
536: Set L=X,VALUE=X+1
537: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
538: For K=2:1 Set L=L*X/K,VALUE=VALUE+L Quit:($Translate(L,"-")<LIM)
539: Quit VALUE
540: ;===
541: ;
542: ;
543: LOG(X,PREC) ;
544: New L,LIM,M,N,K,VALUE
545: If X'>0 Set $Ecode=",M28,"
546: Set PREC=$Get(PREC,11)
547: Set M=1
548: ;
549: For N=0:1 Quit:(X/M)<10 Set M=M*10
550: ;;;
551: ;
552: If X<1 For N=0:-1 Quit:(X/M)>0.1 Set M=M*0.1
553: Set X=X/M
554: Set X=(X-1)/(X+1),(VALUE,L)=X
555: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
556: For K=3:2 Set L=L*X*X,M=L/K,VALUE=M+VALUE Set:M<0 M=-M Quit:M<LIM
557: Set VALUE=VALUE*2+(N*2.30258509298749)
558: Quit VALUE
559: ;===
560: ;
561: ;
562: LOG10(X,PREC) ;
563: New L,LIM,M,N,K,VALUE
564: If X'>0 Set $Ecode=",M28,"
565: Set PREC=$Get(PREC,11)
566: Set M=1
567: ;
568: For N=0:1 Quit:(X/M)<10 Set M=M*10
569: ;;;
570: ;
571: If X<1 For N=0:-1 Quit:(X/M)>0.1 Set M=M*0.1
572: Set X=X/M
573: Set X=(X-1)/(X+1),(VALUE,L)=X
574: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
575: For K=3:2 Set L=L*X*X,M=L/K,VALUE=M+VALUE Set:M<0 M=-M Quit:M<LIM
576: Set VALUE=VALUE*2+(N*2.30258509298749)
577: Quit VALUE/2.30258509298749
578: ;===
579: ;
580: ;
581: MTXADD(A,B,R,ROWS,COLS) ;
582: ; Add A[ROWS,COLS] to B[ROWS,COLS],
583: ; result goes to R[ROWS,COLS]
584: IF $DATA(A)<10 QUIT 0
585: IF $DATA(B)<10 QUIT 0
586: IF $GET(ROWS)<1 QUIT 0
587: IF $GET(COLS)<1 QUIT 0
588: ;
589: NEW ROW,COL,ANY
590: FOR ROW=1:1:ROWS FOR COL=1:1:COLS DO
591: . KVALUE R(ROW,COL) SET ANY=0
592: . SET:$DATA(A(ROW,COL))#2 ANY=1
593: . SET:$DATA(B(ROW,COL))#2 ANY=1
594: . SET:ANY R(ROW,COL)=$GET(A(ROW,COL))+$GET(B(ROW,COL))
595: . QUIT
596: QUIT 1
597: ;===
598: ;
599: ;
600: MTXCOF(A,I,K,N) ;
601: ; Compute cofactor for element [i,k]
602: ; in matrix A[N,N]
603: NEW T,R,C,RR,CC
604: SET CC=0 FOR C=1:1:N DO:C'=K
605: . SET CC=CC+1,RR=0
606: . FOR R=1:1:N SET:R'=I RR=RR+1,T(RR,CC)=$GET(A(R,C))
607: . QUIT
608: QUIT $$MTXDET(.T,N-1)
609: ;===
610: ;
611: ;
612: MTXCOPY(A,R,ROWS,COLS) ;
613: ; Copy A[ROWS,COLS] to R[ROWS,COLS]
614: IF $DATA(A)<10 QUIT 0
615: IF $GET(ROWS)<1 QUIT 0
616: IF $GET(COLS)<1 QUIT 0
617: ;
618: NEW ROW,COL
619: FOR ROW=1:1:ROWS FOR COL=1:1:COLS DO
620: . KVALUE R(ROW,COL)
621: . SET:$DATA(A(ROW,COL))#2 R(ROW,COL)=A(ROW,COL)
622: . QUIT
623: QUIT 1
624: ;===
625: ;
626: ;
627: MTXDET(A,N) ;
628: ; Compute determinant of matrix A[N,N]
629: IF $DATA(A)<10 QUIT ""
630: IF N<1 QUIT ""
631: ;
632: ; First the simple cases
633: ;
634: IF N=1 QUIT $GET(A(1,1))
635: IF N=2 QUIT $GET(A(1,1))*$GET(A(2,2))-($GET(A(1,2))*$GET(A(2,1)))
636: ;
637: NEW DET,I,SIGN
638: ;
639: ; Det A = sum (k=1:n) element (i,k) * cofactor [i,k]
640: ;
641: SET DET=0,SIGN=1
642: FOR I=1:1:N DO
643: . SET DET=$GET(A(1,I))*$$MTXCOF(.A,1,I,N)*SIGN+DET
644: . SET SIGN=-SIGN
645: . QUIT
646: QUIT DET
647: ;===
648: ;
649: ;
650: MTXEQU(A,B,R,N,M) ;
651: ; Solve matrix equation A [M,M] * R [M,N] = B [M,N]
652: IF $GET(M)<1 QUIT ""
653: IF $GET(N)<1 QUIT ""
654: IF '$$MTXDET(.A) QUIT 0
655: ;
656: NEW I,I1,J,J1,J2,K,L,T,T1,T2,TEMP,X
657: ;
658: SET X=$$MTXCOPY(.A,.T,N,N)
659: SET X=$$MTXCOPY(.B,.R,N,M)
660: ;
661: ; Reduction of matrix A
662: ; Steps of reduction are counted by index K
663: ;
664: FOR K=1:1:N-1 DO
665: . ;
666: . ; Search for largest coefficient of T
667: . ; (denoted by TEMP)
668: . ; in first column of reduced system
669: . ;
670: . SET TEMP=0,J2=K
671: . FOR J1=K:1:N DO
672: . . QUIT:$TRANSLATE($GET(T(J1,K)),"-")>$TRANSLATE(TEMP,"-")
673: . . SET TEMP=T(J1,K),J2=J1
674: . . QUIT
675: . ;
676: . ; Exchange row number K with row number J2,
677: . ; if necessary
678: . ;
679: . DO:J2'=K
680: . . ;
681: . . FOR J=K:1:N DO
682: . . . SET T1=$GET(T(K,J)),T2=$GET(T(J2,J))
683: . . . KILL T(K,J),T(J2,J)
684: . . . IF T1'="" SET T(J2,J)=T1
685: . . . IF T2'="" SET T(K,J)=T2
686: . . . QUIT
687: . . FOR J=1:1:M DO
688: . . . SET T1=$GET(R(K,J)),T2=$GET(R(J2,J))
689: . . . KILL R(K,J),R(J2,J)
690: . . . IF T1'="" SET R(J2,J)=T1
691: . . . IF T2'="" SET R(K,J)=T2
692: . . . QUIT
693: . . QUIT
694: . ;
695: . ; Actual reduction
696: . ;
697: . FOR I=K+1:1:N DO
698: . . FOR J=K+1:1:N DO
699: . . . QUIT:'$GET(T(K,K))
700: . . . SET T(I,J)=-$GET(T(K,J))*$GET(T(I,K))/T(K,K)+$GET(T(I,J))
701: . . . QUIT
702: . . FOR J=1:1:M DO
703: . . . QUIT:'$GET(T(K,K))
704: . . . SET R(I,J)=-$GET(R(K,J))*$GET(T(I,K))/T(K,K)+$GET(R(I,J))
705: . . . QUIT
706: . . QUIT
707: . QUIT
708: ;
709: ; Backsubstitution
710: ;
711: FOR J=1:1:M DO
712: . IF $GET(T(N,N)) SET R(N,J)=$GET(R(N,J))/T(N,N)
713: . IF N-1>0 FOR I1=1:1:N-1 DO
714: . . SET I=N-I1
715: . . FOR L=I+1:1:N DO
716: . . . SET R(I,J)=-$GET(T(I,L))*$GET(R(L,J))+$GET(R(I,J))
717: . . . QUIT
718: . . IF $GET(T(I,I)) SET R(I,J)=$GET(R(I,J))/$GET(T(I,I))
719: . . QUIT
720: . QUIT
721: QUIT $$MTXDET(.R)
722: ;===
723: ;
724: ;
725: MTXINV(A,R,N) ;
726: ; Invert A[N,N], result goes to R[N,N]
727: IF $DATA(A)<10 QUIT 0
728: IF $GET(N)<1 QUIT 0
729: ;
730: NEW T,X
731: SET X=$$MTXUNIT(.T,N)
732: QUIT $$MTXEQU(.A,.T,.R,N,N)
733: ;===
734: ;
735: ;
736: MTXMUL(A,B,R,M,L,N) ;
737: ; Multiply A[M,L] by B[L,N], result goes to R[M,N]
738: IF $DATA(A)<10 QUIT 0
739: IF $DATA(B)<10 QUIT 0
740: IF $GET(L)<1 QUIT 0
741: IF $GET(M)<1 QUIT 0
742: IF $GET(N)<1 QUIT 0
743: ;
744: NEW I,J,K,SUM,ANY
745: FOR I=1:1:M FOR J=1:1:N DO
746: . SET (SUM,ANY)=0
747: . KVALUE R(I,J)
748: . FOR K=1:1:L DO
749: . . SET:$DATA(A(I,K))#2 ANY=1
750: . . SET:$DATA(B(K,J))#2 ANY=1
751: . . SET SUM=$GET(A(I,K))*$GET(B(K,J))+SUM
752: . . QUIT
753: . SET:ANY R(I,J)=SUM
754: . QUIT
755: QUIT 1
756: ;===
757: ;
758: ;
759: MTXSCA(A,R,ROWS,COLS,S) ;
760: ; Multiply A[ROWS,COLS] with the scalar S,
761: ; result goes to R[ROWS,COLS]
762: IF $DATA(A)<10 QUIT 0
763: IF $GET(ROWS)<1 QUIT 0
764: IF $GET(COLS)<1 QUIT 0
765: IF '($DATA(S)#2) QUIT 0
766: ;
767: NEW ROW,COL
768: FOR ROW=1:1:ROWS FOR COL=1:1:COLS DO
769: . KVALUE R(ROW,COL)
770: . SET:$DATA(A(ROW,COL))#2 R(ROW,COL)=A(ROW,COL)*S
771: . QUIT
772: QUIT 1
773: ;===
774: ;
775: ;
776: MTXSUB(A,B,R,ROWS,COLS) ;
777: ; Subtract B[ROWS,COLS] from A[ROWS,COLS],
778: ; result goes to R[ROWS,COLS]
779: IF $DATA(A)<10 QUIT 0
780: IF $DATA(B)<10 QUIT 0
781: IF $GET(ROWS)<1 QUIT 0
782: IF $GET(COLS)<1 QUIT 0
783: ;
784: NEW ROW,COL,ANY
785: FOR ROW=1:1:ROWS FOR COL=1:1:COLS DO
786: . KVALUE R(ROW,COL) SET ANY=0
787: . SET:$DATA(A(ROW,COL))#2 ANY=1
788: . SET:$DATA(B(ROW,COL))#2 ANY=1
789: . ;
790: . SET:ANY R(ROW,COL)=$GET(A(ROW,COL))-$GET(B(ROW,COL))
791: . ;;;
792: . ;
793: . QUIT
794: QUIT 1
795: ;===
796: ;
797: ;
798: MTXTRP(A,R,M,N) ;
799: ; Transpose A[M,N], result goes to R[N,M]
800: IF $DATA(A)<10 QUIT 0
801: IF $GET(M)<1 QUIT 0
802: IF $GET(N)<1 QUIT 0
803: ;
804: NEW I,J,K,D1,V1,D2,V2
805: FOR I=1:1:M+N-1 FOR J=1:1:I+1\2 DO
806: . SET K=I-J+1
807: . IF K=J DO QUIT
808: . . SET V1=$GET(A(J,J)),D1=$DATA(A(J,J))#2
809: . . IF J'>N,J'>M KVALUE R(J,J) SET:D1 R(J,J)=V1
810: . . QUIT
811: . ;
812: . SET V1=$GET(A(K,J)),D1=$DATA(A(K,J))#2
813: . SET V2=$GET(A(J,K)),D2=$DATA(A(J,K))#2
814: . IF K'>M,J'>N KVALUE R(K,J) SET:D2 R(K,J)=V2
815: . IF J'>M,K'>N KVALUE R(J,K) SET:D1 R(J,K)=V1
816: . QUIT
817: QUIT 1
818: ;===
819: ;
820: ;
821: MTXUNIT(R,N,SPARSE) ;
822: ; Create a unit matrix R[N,N]
823: IF $GET(N)<1 QUIT 0
824: ;
825: NEW ROW,COL
826: FOR ROW=1:1:N FOR COL=1:1:N DO
827: . KVALUE R(ROW,COL)
828: . IF $GET(SPARSE) QUIT:ROW'=COL
829: . SET R(ROW,COL)=$SELECT(ROW=COL:1,1:0)
830: . QUIT
831: QUIT 1
832: ;===
833: ;
834: ;
835: PI() Quit 3.14159265358979
836: ;===
837: ;
838: ;
839: RADDEG(X) Quit X*180/3.14159265358979
840: ;===
841: ;
842: ;
843: SEC(X,PREC) ;
844: New L,LIM,K,SIGN,VALUE
845: ;
846: Set:X[":" X=$$DMSDEC(X)
847: ;;;
848: ;
849: Set PREC=$Get(PREC,11)
850: Set X=X#(2*$$PI())
851: Set (VALUE,L)=1,SIGN=-1
852: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
853: For K=2:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
854: . Set L=L*X*X/(K-1*K),VALUE=VALUE+(SIGN*L)
855: . Quit
856: If 'VALUE Quit "INFINITE"
857: Quit 1/VALUE
858: ;===
859: ;
860: ;
861: SECH(X,PREC)
862: Quit 1/$$COSH(X,$Get(PREC,11))
863: ;;;
864: ;===
865: ;
866: ;
867: SIGN(X) Quit $SELECT(X<0:-1,X>0:1,1:0)
868: ;===
869: ;
870: ;
871: SIN(X,PREC) ;
872: I '$D(PREC) Q $$%SIN(X)
873: New L,LIM,K,SIGN,VALUE
874: ;
875: Set:X[":" X=$$DMSDEC(X)
876: ;;;
877: ;
878: Set PREC=$Get(PREC,11)
879: Set X=X#(2*$$PI())
880: Set (VALUE,L)=X,SIGN=-1
881: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
882: For K=3:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
883: . Set L=L/(K-1)*X/K*X,VALUE=VALUE+(SIGN*L)
884: . Quit
885: Quit VALUE
886: ;===
887: ;
888: ;
889: %SIN(X) ;
890: ;
891: New A,N,PI,R,SIGN,XX
892: ;
893: ; This approximation only works for 0 <= x <= pi/2
894: ; so reduce angle to correct quadrant.
895: ;
896: Set PI=$$PI(),X=X#(PI*2),SIGN=1
897: Set:X>PI X=2*PI-X,SIGN=-1
898: ;
899: Set:X*2<PI X=PI-X
900: ;;;
901: ;
902: ;
903: Set XX=X*X,A(1)=-0.4999999963,A(2)=0.0416666418
904: Set A(3)=-0.0013888397,A(4)=0.0000247609,A(5)=-0.0000002605
905: Set (X,R)=1 For N=1:1:5 Set X=X*XX,R=A(N)*X+R
906: Quit R*SIGN
907: ;===
908: ;
909: ;
910: SINH(X,PREC) ;
911: ;
912: New E,F,I,P,R,T,XX
913: ;;;
914: ;
915: Set PREC=$Get(PREC,11)+1
916: Set @("E=1E-"_PREC)
917: Set XX=X*X,F=1,I=2,(P,R,T)=X
918: For Set T=T*XX,F=I+1*I*F,R=T/F+R,P=P-R/R,I=I+2 If -E<P,P<E Quit
919: Quit R
920: ;===
921: ;
922: ;
923: SQRT(X,PREC) ;
924: If X<0 Set $Ecode=",M28,"
925: If X=0 Quit 0
926: ;
927: Set PREC=$Get(PREC,11)
928: ;;;
929: ;
930: ;
931: If X<1 Quit 1/$$SQRT(1/X,PREC)
932: ;;;
933: ;
934: New P,R,E
935: Set PREC=$Get(PREC,11)+1
936: ;
937: Set @("E=1E-"_PREC)
938: ;;;
939: ;
940: Set R=X
941: For Set P=R,R=X/R+R/2,P=P-R/R If -E<P,P<E Quit
942: Quit R
943: ;===
944: ;
945: ;
946: TAN(X,PREC) ;
947: New L,LIM,K,S,SIGN,VALUE
948: ;
949: Set:X[":" X=$$DMSDEC(X)
950: ;;;
951: ;
952: Set PREC=$Get(PREC,11)
953: Set X=X#(2*$$PI())
954: Set (VALUE,L)=X,SIGN=-1
955: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
956: For K=3:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
957: . Set L=L/(K-1)*X/K*X,VALUE=VALUE+(SIGN*L)
958: . Quit
959: Set S=VALUE
960: Set X=X#(2*$$PI())
961: Set (VALUE,L)=1,SIGN=-1
962: Set LIM=$Select((PREC+3)'>11:PREC+3,1:11),@("LIM=1E-"_LIM)
963: For K=2:2 Do Quit:($Translate(L,"-")<LIM) Set SIGN=SIGN*-1
964: . Set L=L*X*X/(K-1*K),VALUE=VALUE+(SIGN*L)
965: . Quit
966: If 'VALUE Quit "INFINITE"
967: Quit S/VALUE
968: ;===
969: ;
970: ;
971: TANH(X,PREC) ;
972: ;
973: Set PREC=$Get(PREC,11)
974: ;;;
975: ;
976: Quit $$SINH(X,PREC)/$$COSH(X,PREC)
977: ;===
978:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>