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>