github.com/gopherd/gonum@v0.0.4/mathext/internal/amos/amos.go (about) 1 // Copyright ©2016 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package amos 6 7 import ( 8 "math" 9 "math/cmplx" 10 ) 11 12 /* 13 The AMOS functions are included in SLATEC, and the SLATEC guide (http://www.netlib.org/slatec/guide) explicitly states: 14 "The Library is in the public domain and distributed by the Energy 15 Science and Technology Software Center." 16 Mention of AMOS's inclusion in SLATEC goes back at least to this 1985 technical report from Sandia National Labs: http://infoserve.sandia.gov/sand_doc/1985/851018.pdf 17 */ 18 19 // math.NaN() are for padding to keep indexing easy. 20 var imach = []int{-0, 5, 6, 0, 0, 32, 4, 2, 31, 2147483647, 2, 24, -125, 127, 53, -1021, 1023} 21 22 var dmach = []float64{math.NaN(), 2.23e-308, 1.79e-308, 1.11e-16, 2.22e-16, 0.30103000998497009} 23 24 func abs(a int) int { 25 if a >= 0 { 26 return a 27 } 28 return -a 29 } 30 31 func min(a, b int) int { 32 if a < b { 33 return a 34 } 35 return b 36 } 37 38 func max(a, b int) int { 39 if a > b { 40 return a 41 } 42 return b 43 } 44 45 func Zairy(ZR, ZI float64, ID, KODE int) (AIR, AII float64, NZ, IERR int) { 46 // zairy is adapted from the original Netlib code by Donald Amos. 47 // http://www.netlib.no/netlib/amos/zairy.f 48 49 // Original comment: 50 /* 51 C***BEGIN PROLOGUE ZAIRY 52 C***DATE WRITTEN 830501 (YYMMDD) 53 C***REVISION DATE 890801 (YYMMDD) 54 C***CATEGORY NO. B5K 55 C***KEYWORDS AIRY FUNCTION,BESSEL FUNCTIONS OF ORDER ONE THIRD 56 C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES 57 C***PURPOSE TO COMPUTE AIRY FUNCTIONS AI(Z) AND DAI(Z) FOR COMPLEX Z 58 C***DESCRIPTION 59 C 60 C ***A DOUBLE PRECISION ROUTINE*** 61 C ON KODE=1, ZAIRY COMPUTES THE COMPLEX AIRY FUNCTION AI(Z) OR 62 C ITS DERIVATIVE DAI(Z)/DZ ON ID=0 OR ID=1 RESPECTIVELY. ON 63 C KODE=2, A SCALING OPTION CEXP(ZTA)*AI(Z) OR CEXP(ZTA)* 64 C DAI(Z)/DZ IS PROVIDED TO REMOVE THE EXPONENTIAL DECAY IN 65 C -PI/3<ARG(Z)<PI/3 AND THE EXPONENTIAL GROWTH IN 66 C PI/3<ABS(ARG(Z))<PI WHERE ZTA=(2/3)*Z*CSQRT(Z). 67 C 68 C WHILE THE AIRY FUNCTIONS AI(Z) AND DAI(Z)/DZ ARE ANALYTIC IN 69 C THE WHOLE Z PLANE, THE CORRESPONDING SCALED FUNCTIONS DEFINED 70 C FOR KODE=2 HAVE A CUT ALONG THE NEGATIVE REAL AXIS. 71 C DEFINTIONS AND NOTATION ARE FOUND IN THE NBS HANDBOOK OF 72 C MATHEMATICAL FUNCTIONS (REF. 1). 73 C 74 C INPUT ZR,ZI ARE DOUBLE PRECISION 75 C ZR,ZI - Z=CMPLX(ZR,ZI) 76 C ID - ORDER OF DERIVATIVE, ID=0 OR ID=1 77 C KODE - A PARAMETER TO INDICATE THE SCALING OPTION 78 C KODE= 1 returnS 79 C AI=AI(Z) ON ID=0 OR 80 C AI=DAI(Z)/DZ ON ID=1 81 C = 2 returnS 82 C AI=CEXP(ZTA)*AI(Z) ON ID=0 OR 83 C AI=CEXP(ZTA)*DAI(Z)/DZ ON ID=1 WHERE 84 C ZTA=(2/3)*Z*CSQRT(Z) 85 C 86 C OUTPUT AIR,AII ARE DOUBLE PRECISION 87 C AIR,AII- COMPLEX ANSWER DEPENDING ON THE CHOICES FOR ID AND 88 C KODE 89 C NZ - UNDERFLOW INDICATOR 90 C NZ= 0 , NORMAL return 91 C NZ= 1 , AI=CMPLX(0.0E0,0.0E0) DUE TO UNDERFLOW IN 92 C -PI/3<ARG(Z)<PI/3 ON KODE=1 93 C IERR - ERROR FLAG 94 C IERR=0, NORMAL return - COMPUTATION COMPLETED 95 C IERR=1, INPUT ERROR - NO COMPUTATION 96 C IERR=2, OVERFLOW - NO COMPUTATION, REAL(ZTA) 97 C TOO LARGE ON KODE=1 98 C IERR=3, CABS(Z) LARGE - COMPUTATION COMPLETED 99 C LOSSES OF SIGNIFCANCE BY ARGUMENT REDUCTION 100 C PRODUCE LESS THAN HALF OF MACHINE ACCURACY 101 C IERR=4, CABS(Z) TOO LARGE - NO COMPUTATION 102 C COMPLETE LOSS OF ACCURACY BY ARGUMENT 103 C REDUCTION 104 C IERR=5, ERROR - NO COMPUTATION, 105 C ALGORITHM TERMINATION CONDITION NOT MET 106 C 107 C***LONG DESCRIPTION 108 C 109 C AI AND DAI ARE COMPUTED FOR CABS(Z)>1.0 FROM THE K BESSEL 110 C FUNCTIONS BY 111 C 112 C AI(Z)=C*SQRT(Z)*K(1/3,ZTA) , DAI(Z)=-C*Z*K(2/3,ZTA) 113 C C=1.0/(PI*SQRT(3.0)) 114 C ZTA=(2/3)*Z**(3/2) 115 C 116 C WITH THE POWER SERIES FOR CABS(Z)<=1.0. 117 C 118 C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE- 119 C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z IS LARGE, LOSSES 120 C OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. CONSEQUENTLY, IF 121 C THE MAGNITUDE OF ZETA=(2/3)*Z**1.5 EXCEEDS U1=SQRT(0.5/UR), 122 C THEN LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR 123 C FLAG IERR=3 IS TRIGGERED WHERE UR=math.Max(dmach[4),1.0D-18) IS 124 C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION. 125 C ALSO, if THE MAGNITUDE OF ZETA IS LARGER THAN U2=0.5/UR, THEN 126 C ALL SIGNIFICANCE IS LOST AND IERR=4. IN ORDER TO USE THE INT 127 C FUNCTION, ZETA MUST BE FURTHER RESTRICTED NOT TO EXCEED THE 128 C LARGEST INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF ZETA 129 C MUST BE RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2, 130 C AND U3 ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE 131 C PRECISION ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE 132 C PRECISION ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMIT- 133 C ING IN THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT THE MAG- 134 C NITUDE OF Z CANNOT EXCEED 3.1E+4 IN SINGLE AND 2.1E+6 IN 135 C DOUBLE PRECISION ARITHMETIC. THIS ALSO MEANS THAT ONE CAN 136 C EXPECT TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES, 137 C NO DIGITS IN SINGLE PRECISION AND ONLY 7 DIGITS IN DOUBLE 138 C PRECISION ARITHMETIC. SIMILAR CONSIDERATIONS HOLD FOR OTHER 139 C MACHINES. 140 C 141 C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX 142 C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT 143 C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE- 144 C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE 145 C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))), 146 C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF 147 C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY 148 C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN 149 C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY 150 C SEVERAL ORDERS OF MAGNITUDE. if ONE COMPONENT IS 10**K LARGER 151 C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K, 152 C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS 153 C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER 154 C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY 155 C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER 156 C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE 157 C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES, 158 C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P, 159 C OR -PI/2+P. 160 C 161 C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ 162 C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF 163 C COMMERCE, 1955. 164 C 165 C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT 166 C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983 167 C 168 C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX 169 C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85- 170 C 1018, MAY, 1985 171 C 172 C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX 173 C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS. 174 C MATH. SOFTWARE, 1986 175 */ 176 var AI, CONE, CSQ, CY, S1, S2, TRM1, TRM2, Z, ZTA, Z3 complex128 177 var AA, AD, AK, ALIM, ATRM, AZ, AZ3, BK, 178 CC, CK, COEF, CONEI, CONER, CSQI, CSQR, C1, C2, DIG, 179 DK, D1, D2, ELIM, FID, FNU, PTR, RL, R1M5, SFAC, STI, STR, 180 S1I, S1R, S2I, S2R, TOL, TRM1I, TRM1R, TRM2I, TRM2R, TTH, ZEROI, 181 ZEROR, ZTAI, ZTAR, Z3I, Z3R, ALAZ, BB float64 182 var IFLAG, K, K1, K2, MR, NN int 183 var tmp complex128 184 185 // Extra element for padding. 186 CYR := []float64{math.NaN(), 0} 187 CYI := []float64{math.NaN(), 0} 188 189 _ = AI 190 _ = CONE 191 _ = CSQ 192 _ = CY 193 _ = S1 194 _ = S2 195 _ = TRM1 196 _ = TRM2 197 _ = Z 198 _ = ZTA 199 _ = Z3 200 201 TTH = 6.66666666666666667e-01 202 C1 = 3.55028053887817240e-01 203 C2 = 2.58819403792806799e-01 204 COEF = 1.83776298473930683e-01 205 ZEROR = 0 206 ZEROI = 0 207 CONER = 1 208 CONEI = 0 209 210 NZ = 0 211 if ID < 0 || ID > 1 { 212 IERR = 1 213 } 214 if KODE < 1 || KODE > 2 { 215 IERR = 1 216 } 217 if IERR != 0 { 218 return 219 } 220 AZ = cmplx.Abs(complex(ZR, ZI)) 221 TOL = math.Max(dmach[4], 1.0e-18) 222 FID = float64(ID) 223 if AZ > 1.0e0 { 224 goto Seventy 225 } 226 227 // POWER SERIES FOR CABS(Z)<=1. 228 S1R = CONER 229 S1I = CONEI 230 S2R = CONER 231 S2I = CONEI 232 if AZ < TOL { 233 goto OneSeventy 234 } 235 AA = AZ * AZ 236 if AA < TOL/AZ { 237 goto Forty 238 } 239 TRM1R = CONER 240 TRM1I = CONEI 241 TRM2R = CONER 242 TRM2I = CONEI 243 ATRM = 1.0e0 244 STR = ZR*ZR - ZI*ZI 245 STI = ZR*ZI + ZI*ZR 246 Z3R = STR*ZR - STI*ZI 247 Z3I = STR*ZI + STI*ZR 248 AZ3 = AZ * AA 249 AK = 2.0e0 + FID 250 BK = 3.0e0 - FID - FID 251 CK = 4.0e0 - FID 252 DK = 3.0e0 + FID + FID 253 D1 = AK * DK 254 D2 = BK * CK 255 AD = math.Min(D1, D2) 256 AK = 24.0e0 + 9.0e0*FID 257 BK = 30.0e0 - 9.0e0*FID 258 for K = 1; K <= 25; K++ { 259 STR = (TRM1R*Z3R - TRM1I*Z3I) / D1 260 TRM1I = (TRM1R*Z3I + TRM1I*Z3R) / D1 261 TRM1R = STR 262 S1R = S1R + TRM1R 263 S1I = S1I + TRM1I 264 STR = (TRM2R*Z3R - TRM2I*Z3I) / D2 265 TRM2I = (TRM2R*Z3I + TRM2I*Z3R) / D2 266 TRM2R = STR 267 S2R = S2R + TRM2R 268 S2I = S2I + TRM2I 269 ATRM = ATRM * AZ3 / AD 270 D1 = D1 + AK 271 D2 = D2 + BK 272 AD = math.Min(D1, D2) 273 if ATRM < TOL*AD { 274 goto Forty 275 } 276 AK = AK + 18.0e0 277 BK = BK + 18.0e0 278 } 279 Forty: 280 if ID == 1 { 281 goto Fifty 282 } 283 AIR = S1R*C1 - C2*(ZR*S2R-ZI*S2I) 284 AII = S1I*C1 - C2*(ZR*S2I+ZI*S2R) 285 if KODE == 1 { 286 return 287 } 288 tmp = cmplx.Sqrt(complex(ZR, ZI)) 289 STR = real(tmp) 290 STI = imag(tmp) 291 ZTAR = TTH * (ZR*STR - ZI*STI) 292 ZTAI = TTH * (ZR*STI + ZI*STR) 293 tmp = cmplx.Exp(complex(ZTAR, ZTAI)) 294 STR = real(tmp) 295 STI = imag(tmp) 296 PTR = AIR*STR - AII*STI 297 AII = AIR*STI + AII*STR 298 AIR = PTR 299 return 300 301 Fifty: 302 AIR = -S2R * C2 303 AII = -S2I * C2 304 if AZ <= TOL { 305 goto Sixty 306 } 307 STR = ZR*S1R - ZI*S1I 308 STI = ZR*S1I + ZI*S1R 309 CC = C1 / (1.0e0 + FID) 310 AIR = AIR + CC*(STR*ZR-STI*ZI) 311 AII = AII + CC*(STR*ZI+STI*ZR) 312 313 Sixty: 314 if KODE == 1 { 315 return 316 } 317 tmp = cmplx.Sqrt(complex(ZR, ZI)) 318 STR = real(tmp) 319 STI = imag(tmp) 320 ZTAR = TTH * (ZR*STR - ZI*STI) 321 ZTAI = TTH * (ZR*STI + ZI*STR) 322 tmp = cmplx.Exp(complex(ZTAR, ZTAI)) 323 STR = real(tmp) 324 STI = imag(tmp) 325 PTR = STR*AIR - STI*AII 326 AII = STR*AII + STI*AIR 327 AIR = PTR 328 return 329 330 // CASE FOR CABS(Z)>1.0. 331 Seventy: 332 FNU = (1.0e0 + FID) / 3.0e0 333 334 /* 335 SET PARAMETERS RELATED TO MACHINE CONSTANTS. 336 TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0D-18. 337 ELIM IS THE APPROXIMATE EXPONENTIAL OVER-&&UNDERFLOW LIMIT. 338 EXP(-ELIM)<EXP(-ALIM)=EXP(-ELIM)/TOL AND 339 EXP(ELIM)>EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR 340 UNDERFLOW&&OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE. 341 RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LA>=Z. 342 DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG). 343 */ 344 K1 = imach[15] 345 K2 = imach[16] 346 R1M5 = dmach[5] 347 348 K = min(abs(K1), abs(K2)) 349 ELIM = 2.303e0 * (float64(K)*R1M5 - 3.0e0) 350 K1 = imach[14] - 1 351 AA = R1M5 * float64(K1) 352 DIG = math.Min(AA, 18.0e0) 353 AA = AA * 2.303e0 354 ALIM = ELIM + math.Max(-AA, -41.45e0) 355 RL = 1.2e0*DIG + 3.0e0 356 ALAZ = math.Log(AZ) 357 358 // TEST FOR PROPER RANGE. 359 AA = 0.5e0 / TOL 360 BB = float64(float32(imach[9])) * 0.5e0 361 AA = math.Min(AA, BB) 362 AA = math.Pow(AA, TTH) 363 if AZ > AA { 364 goto TwoSixty 365 } 366 AA = math.Sqrt(AA) 367 if AZ > AA { 368 IERR = 3 369 } 370 tmp = cmplx.Sqrt(complex(ZR, ZI)) 371 CSQR = real(tmp) 372 CSQI = imag(tmp) 373 ZTAR = TTH * (ZR*CSQR - ZI*CSQI) 374 ZTAI = TTH * (ZR*CSQI + ZI*CSQR) 375 376 // RE(ZTA)<=0 WHEN RE(Z)<0, ESPECIALLY WHEN IM(Z) IS SMALL. 377 IFLAG = 0 378 SFAC = 1.0e0 379 AK = ZTAI 380 if ZR >= 0.0e0 { 381 goto Eighty 382 } 383 BK = ZTAR 384 CK = -math.Abs(BK) 385 ZTAR = CK 386 ZTAI = AK 387 388 Eighty: 389 if ZI != 0.0e0 { 390 goto Ninety 391 } 392 if ZR > 0.0e0 { 393 goto Ninety 394 } 395 ZTAR = 0.0e0 396 ZTAI = AK 397 Ninety: 398 AA = ZTAR 399 if AA >= 0.0e0 && ZR > 0.0e0 { 400 goto OneTen 401 } 402 if KODE == 2 { 403 goto OneHundred 404 } 405 406 // OVERFLOW TEST. 407 if AA > (-ALIM) { 408 goto OneHundred 409 } 410 AA = -AA + 0.25e0*ALAZ 411 IFLAG = 1 412 SFAC = TOL 413 if AA > ELIM { 414 goto TwoSeventy 415 } 416 417 OneHundred: 418 // CBKNU AND CACON return EXP(ZTA)*K(FNU,ZTA) ON KODE=2. 419 MR = 1 420 if ZI < 0.0e0 { 421 MR = -1 422 } 423 _, _, _, _, _, _, CYR, CYI, NN, _, _, _, _ = Zacai(ZTAR, ZTAI, FNU, KODE, MR, 1, CYR, CYI, RL, TOL, ELIM, ALIM) 424 if NN < 0 { 425 goto TwoEighty 426 } 427 NZ = NZ + NN 428 goto OneThirty 429 430 OneTen: 431 if KODE == 2 { 432 goto OneTwenty 433 } 434 435 // UNDERFLOW TEST. 436 if AA < ALIM { 437 goto OneTwenty 438 } 439 AA = -AA - 0.25e0*ALAZ 440 IFLAG = 2 441 SFAC = 1.0e0 / TOL 442 if AA < (-ELIM) { 443 goto TwoTen 444 } 445 OneTwenty: 446 _, _, _, _, _, CYR, CYI, NZ, _, _, _ = Zbknu(ZTAR, ZTAI, FNU, KODE, 1, CYR, CYI, TOL, ELIM, ALIM) 447 448 OneThirty: 449 S1R = CYR[1] * COEF 450 S1I = CYI[1] * COEF 451 if IFLAG != 0 { 452 goto OneFifty 453 } 454 if ID == 1 { 455 goto OneFourty 456 } 457 AIR = CSQR*S1R - CSQI*S1I 458 AII = CSQR*S1I + CSQI*S1R 459 return 460 OneFourty: 461 AIR = -(ZR*S1R - ZI*S1I) 462 AII = -(ZR*S1I + ZI*S1R) 463 return 464 OneFifty: 465 S1R = S1R * SFAC 466 S1I = S1I * SFAC 467 if ID == 1 { 468 goto OneSixty 469 } 470 STR = S1R*CSQR - S1I*CSQI 471 S1I = S1R*CSQI + S1I*CSQR 472 S1R = STR 473 AIR = S1R / SFAC 474 AII = S1I / SFAC 475 return 476 OneSixty: 477 STR = -(S1R*ZR - S1I*ZI) 478 S1I = -(S1R*ZI + S1I*ZR) 479 S1R = STR 480 AIR = S1R / SFAC 481 AII = S1I / SFAC 482 return 483 OneSeventy: 484 AA = 1.0e+3 * dmach[1] 485 S1R = ZEROR 486 S1I = ZEROI 487 if ID == 1 { 488 goto OneNinety 489 } 490 if AZ <= AA { 491 goto OneEighty 492 } 493 S1R = C2 * ZR 494 S1I = C2 * ZI 495 OneEighty: 496 AIR = C1 - S1R 497 AII = -S1I 498 return 499 OneNinety: 500 AIR = -C2 501 AII = 0.0e0 502 AA = math.Sqrt(AA) 503 if AZ <= AA { 504 goto TwoHundred 505 } 506 S1R = 0.5e0 * (ZR*ZR - ZI*ZI) 507 S1I = ZR * ZI 508 TwoHundred: 509 AIR = AIR + C1*S1R 510 AII = AII + C1*S1I 511 return 512 TwoTen: 513 NZ = 1 514 AIR = ZEROR 515 AII = ZEROI 516 return 517 TwoSeventy: 518 NZ = 0 519 IERR = 2 520 return 521 TwoEighty: 522 if NN == (-1) { 523 goto TwoSeventy 524 } 525 NZ = 0 526 IERR = 5 527 return 528 TwoSixty: 529 IERR = 4 530 NZ = 0 531 return 532 } 533 534 // sbknu computes the k bessel function in the right half z plane. 535 func Zbknu(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, TOL, ELIM, ALIM float64) (ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, TOLout, ELIMout, ALIMout float64) { 536 /* Old dimension comment. 537 DIMENSION YR(N), YI(N), CC(8), CSSR(3), CSRR(3), BRY(3), CYR(2), 538 * CYI(2) 539 */ 540 541 // TODO(btracey): Find which of these are inputs/outputs/both and clean up 542 // the function call. 543 // YR and YI have length n (but n+1 with better indexing) 544 var AA, AK, ASCLE, A1, A2, BB, BK, CAZ, 545 CBI, CBR, CCHI, CCHR, CKI, CKR, COEFI, COEFR, CONEI, CONER, 546 CRSCR, CSCLR, CSHI, CSHR, CSI, CSR, CTWOR, 547 CZEROI, CZEROR, CZI, CZR, DNU, DNU2, DPI, ETEST, FC, FHS, 548 FI, FK, FKS, FMUI, FMUR, FPI, FR, G1, G2, HPI, PI, PR, PTI, 549 PTR, P1I, P1R, P2I, P2M, P2R, QI, QR, RAK, RCAZ, RTHPI, RZI, 550 RZR, R1, S, SMUI, SMUR, SPI, STI, STR, S1I, S1R, S2I, S2R, TM, 551 TTH, T1, T2, ELM, CELMR, ZDR, ZDI, AS, ALAS, HELIM float64 552 553 var I, IFLAG, INU, K, KFLAG, KK, KMAX, KODED, IDUM, J, IC, INUB, NW int 554 555 var sinh, cosh complex128 556 //var sin, cos float64 557 558 var tmp, p complex128 559 var CSSR, CSRR, BRY [4]float64 560 var CYR, CYI [3]float64 561 562 KMAX = 30 563 CZEROR = 0 564 CZEROI = 0 565 CONER = 1 566 CONEI = 0 567 CTWOR = 2 568 R1 = 2 569 570 DPI = 3.14159265358979324e0 571 RTHPI = 1.25331413731550025e0 572 SPI = 1.90985931710274403e0 573 HPI = 1.57079632679489662e0 574 FPI = 1.89769999331517738e0 575 TTH = 6.66666666666666666e-01 576 577 CC := [9]float64{math.NaN(), 5.77215664901532861e-01, -4.20026350340952355e-02, 578 -4.21977345555443367e-02, 7.21894324666309954e-03, 579 -2.15241674114950973e-04, -2.01348547807882387e-05, 580 1.13302723198169588e-06, 6.11609510448141582e-09} 581 582 CAZ = cmplx.Abs(complex(ZR, ZI)) 583 CSCLR = 1.0e0 / TOL 584 CRSCR = TOL 585 CSSR[1] = CSCLR 586 CSSR[2] = 1.0e0 587 CSSR[3] = CRSCR 588 CSRR[1] = CRSCR 589 CSRR[2] = 1.0e0 590 CSRR[3] = CSCLR 591 BRY[1] = 1.0e+3 * dmach[1] / TOL 592 BRY[2] = 1.0e0 / BRY[1] 593 BRY[3] = dmach[2] 594 IFLAG = 0 595 KODED = KODE 596 RCAZ = 1.0e0 / CAZ 597 STR = ZR * RCAZ 598 STI = -ZI * RCAZ 599 RZR = (STR + STR) * RCAZ 600 RZI = (STI + STI) * RCAZ 601 INU = int(float32(FNU + 0.5)) 602 DNU = FNU - float64(INU) 603 if math.Abs(DNU) == 0.5e0 { 604 goto OneTen 605 } 606 DNU2 = 0.0e0 607 if math.Abs(DNU) > TOL { 608 DNU2 = DNU * DNU 609 } 610 if CAZ > R1 { 611 goto OneTen 612 } 613 614 // SERIES FOR CABS(Z)<=R1. 615 FC = 1.0e0 616 tmp = cmplx.Log(complex(RZR, RZI)) 617 SMUR = real(tmp) 618 SMUI = imag(tmp) 619 FMUR = SMUR * DNU 620 FMUI = SMUI * DNU 621 tmp = complex(FMUR, FMUI) 622 sinh = cmplx.Sinh(tmp) 623 cosh = cmplx.Cosh(tmp) 624 CSHR = real(sinh) 625 CSHI = imag(sinh) 626 CCHR = real(cosh) 627 CCHI = imag(cosh) 628 if DNU == 0.0e0 { 629 goto Ten 630 } 631 FC = DNU * DPI 632 FC = FC / math.Sin(FC) 633 SMUR = CSHR / DNU 634 SMUI = CSHI / DNU 635 Ten: 636 A2 = 1.0e0 + DNU 637 638 // GAM(1-Z)*GAM(1+Z)=PI*Z/SIN(PI*Z), T1=1/GAM(1-DNU), T2=1/GAM(1+DNU). 639 T2 = math.Exp(-dgamln(A2, IDUM)) 640 T1 = 1.0e0 / (T2 * FC) 641 if math.Abs(DNU) > 0.1e0 { 642 goto Forty 643 } 644 645 // SERIES FOR F0 TO RESOLVE INDETERMINACY FOR SMALL ABS(DNU). 646 AK = 1.0e0 647 S = CC[1] 648 for K = 2; K <= 8; K++ { 649 AK = AK * DNU2 650 TM = CC[K] * AK 651 S = S + TM 652 if math.Abs(TM) < TOL { 653 goto Thirty 654 } 655 } 656 Thirty: 657 G1 = -S 658 goto Fifty 659 Forty: 660 G1 = (T1 - T2) / (DNU + DNU) 661 Fifty: 662 G2 = (T1 + T2) * 0.5e0 663 FR = FC * (CCHR*G1 + SMUR*G2) 664 FI = FC * (CCHI*G1 + SMUI*G2) 665 tmp = cmplx.Exp(complex(FMUR, FMUI)) 666 STR = real(tmp) 667 STI = imag(tmp) 668 PR = 0.5e0 * STR / T2 669 PI = 0.5e0 * STI / T2 670 tmp = complex(0.5, 0) / complex(STR, STI) 671 PTR = real(tmp) 672 PTI = imag(tmp) 673 QR = PTR / T1 674 QI = PTI / T1 675 S1R = FR 676 S1I = FI 677 S2R = PR 678 S2I = PI 679 AK = 1.0e0 680 A1 = 1.0e0 681 CKR = CONER 682 CKI = CONEI 683 BK = 1.0e0 - DNU2 684 if INU > 0 || N > 1 { 685 goto Eighty 686 } 687 688 // GENERATE K(FNU,Z), 0.0E0 <= FNU < 0.5E0 AND N=1. 689 if CAZ < TOL { 690 goto Seventy 691 } 692 tmp = complex(ZR, ZI) * complex(ZR, ZI) 693 CZR = real(tmp) 694 CZI = imag(tmp) 695 CZR = 0.25e0 * CZR 696 CZI = 0.25e0 * CZI 697 T1 = 0.25e0 * CAZ * CAZ 698 Sixty: 699 FR = (FR*AK + PR + QR) / BK 700 FI = (FI*AK + PI + QI) / BK 701 STR = 1.0e0 / (AK - DNU) 702 PR = PR * STR 703 PI = PI * STR 704 STR = 1.0e0 / (AK + DNU) 705 QR = QR * STR 706 QI = QI * STR 707 STR = CKR*CZR - CKI*CZI 708 RAK = 1.0e0 / AK 709 CKI = (CKR*CZI + CKI*CZR) * RAK 710 CKR = STR * RAK 711 S1R = CKR*FR - CKI*FI + S1R 712 S1I = CKR*FI + CKI*FR + S1I 713 A1 = A1 * T1 * RAK 714 BK = BK + AK + AK + 1.0e0 715 AK = AK + 1.0e0 716 if A1 > TOL { 717 goto Sixty 718 } 719 Seventy: 720 YR[1] = S1R 721 YI[1] = S1I 722 if KODED == 1 { 723 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 724 } 725 tmp = cmplx.Exp(complex(ZR, ZI)) 726 STR = real(tmp) 727 STI = imag(tmp) 728 tmp = complex(S1R, S1I) * complex(STR, STI) 729 YR[1] = real(tmp) 730 YI[1] = imag(tmp) 731 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 732 733 // GENERATE K(DNU,Z) AND K(DNU+1,Z) FOR FORWARD RECURRENCE. 734 Eighty: 735 if CAZ < TOL { 736 goto OneHundred 737 } 738 tmp = complex(ZR, ZI) * complex(ZR, ZI) 739 CZR = real(tmp) 740 CZI = imag(tmp) 741 CZR = 0.25e0 * CZR 742 CZI = 0.25e0 * CZI 743 T1 = 0.25e0 * CAZ * CAZ 744 Ninety: 745 FR = (FR*AK + PR + QR) / BK 746 FI = (FI*AK + PI + QI) / BK 747 STR = 1.0e0 / (AK - DNU) 748 PR = PR * STR 749 PI = PI * STR 750 STR = 1.0e0 / (AK + DNU) 751 QR = QR * STR 752 QI = QI * STR 753 STR = CKR*CZR - CKI*CZI 754 RAK = 1.0e0 / AK 755 CKI = (CKR*CZI + CKI*CZR) * RAK 756 CKR = STR * RAK 757 S1R = CKR*FR - CKI*FI + S1R 758 S1I = CKR*FI + CKI*FR + S1I 759 STR = PR - FR*AK 760 STI = PI - FI*AK 761 S2R = CKR*STR - CKI*STI + S2R 762 S2I = CKR*STI + CKI*STR + S2I 763 A1 = A1 * T1 * RAK 764 BK = BK + AK + AK + 1.0e0 765 AK = AK + 1.0e0 766 if A1 > TOL { 767 goto Ninety 768 } 769 OneHundred: 770 KFLAG = 2 771 A1 = FNU + 1.0e0 772 AK = A1 * math.Abs(SMUR) 773 if AK > ALIM { 774 KFLAG = 3 775 } 776 STR = CSSR[KFLAG] 777 P2R = S2R * STR 778 P2I = S2I * STR 779 tmp = complex(P2R, P2I) * complex(RZR, RZI) 780 S2R = real(tmp) 781 S2I = imag(tmp) 782 S1R = S1R * STR 783 S1I = S1I * STR 784 if KODED == 1 { 785 goto TwoTen 786 } 787 tmp = cmplx.Exp(complex(ZR, ZI)) 788 FR = real(tmp) 789 FI = imag(tmp) 790 tmp = complex(S1R, S1I) * complex(FR, FI) 791 S1R = real(tmp) 792 S1I = imag(tmp) 793 tmp = complex(S2R, S2I) * complex(FR, FI) 794 S2R = real(tmp) 795 S2I = imag(tmp) 796 goto TwoTen 797 798 // IFLAG=0 MEANS NO UNDERFLOW OCCURRED 799 // IFLAG=1 MEANS AN UNDERFLOW OCCURRED- COMPUTATION PROCEEDS WITH 800 // KODED=2 AND A TEST FOR ON SCALE VALUES IS MADE DURING FORWARD RECURSION 801 OneTen: 802 tmp = cmplx.Sqrt(complex(ZR, ZI)) 803 STR = real(tmp) 804 STI = imag(tmp) 805 tmp = complex(RTHPI, CZEROI) / complex(STR, STI) 806 COEFR = real(tmp) 807 COEFI = imag(tmp) 808 KFLAG = 2 809 if KODED == 2 { 810 goto OneTwenty 811 } 812 if ZR > ALIM { 813 goto TwoNinety 814 } 815 816 STR = math.Exp(-ZR) * CSSR[KFLAG] 817 //sin, cos = math.Sincos(ZI) 818 STI = -STR * math.Sin(ZI) 819 STR = STR * math.Cos(ZI) 820 tmp = complex(COEFR, COEFI) * complex(STR, STI) 821 COEFR = real(tmp) 822 COEFI = imag(tmp) 823 OneTwenty: 824 if math.Abs(DNU) == 0.5e0 { 825 goto ThreeHundred 826 } 827 // MILLER ALGORITHM FOR CABS(Z)>R1. 828 AK = math.Cos(DPI * DNU) 829 AK = math.Abs(AK) 830 if AK == CZEROR { 831 goto ThreeHundred 832 } 833 FHS = math.Abs(0.25e0 - DNU2) 834 if FHS == CZEROR { 835 goto ThreeHundred 836 } 837 838 // COMPUTE R2=F(E). if CABS(Z)>=R2, USE FORWARD RECURRENCE TO 839 // DETERMINE THE BACKWARD INDEX K. R2=F(E) IS A STRAIGHT LINE ON 840 // 12<=E<=60. E IS COMPUTED FROM 2**(-E)=B**(1-I1MACH(14))= 841 // TOL WHERE B IS THE BASE OF THE ARITHMETIC. 842 T1 = float64(imach[14] - 1) 843 T1 = T1 * dmach[5] * 3.321928094e0 844 T1 = math.Max(T1, 12.0e0) 845 T1 = math.Min(T1, 60.0e0) 846 T2 = TTH*T1 - 6.0e0 847 if ZR != 0.0e0 { 848 goto OneThirty 849 } 850 T1 = HPI 851 goto OneFourty 852 OneThirty: 853 T1 = math.Atan(ZI / ZR) 854 T1 = math.Abs(T1) 855 OneFourty: 856 if T2 > CAZ { 857 goto OneSeventy 858 } 859 // FORWARD RECURRENCE LOOP WHEN CABS(Z)>=R2. 860 ETEST = AK / (DPI * CAZ * TOL) 861 FK = CONER 862 if ETEST < CONER { 863 goto OneEighty 864 } 865 FKS = CTWOR 866 CKR = CAZ + CAZ + CTWOR 867 P1R = CZEROR 868 P2R = CONER 869 for I = 1; I <= KMAX; I++ { 870 AK = FHS / FKS 871 CBR = CKR / (FK + CONER) 872 PTR = P2R 873 P2R = CBR*P2R - P1R*AK 874 P1R = PTR 875 CKR = CKR + CTWOR 876 FKS = FKS + FK + FK + CTWOR 877 FHS = FHS + FK + FK 878 FK = FK + CONER 879 STR = math.Abs(P2R) * FK 880 if ETEST < STR { 881 goto OneSixty 882 } 883 } 884 goto ThreeTen 885 OneSixty: 886 FK = FK + SPI*T1*math.Sqrt(T2/CAZ) 887 FHS = math.Abs(0.25 - DNU2) 888 goto OneEighty 889 OneSeventy: 890 // COMPUTE BACKWARD INDEX K FOR CABS(Z)<R2. 891 A2 = math.Sqrt(CAZ) 892 AK = FPI * AK / (TOL * math.Sqrt(A2)) 893 AA = 3.0e0 * T1 / (1.0e0 + CAZ) 894 BB = 14.7e0 * T1 / (28.0e0 + CAZ) 895 AK = (math.Log(AK) + CAZ*math.Cos(AA)/(1.0e0+0.008e0*CAZ)) / math.Cos(BB) 896 FK = 0.12125e0*AK*AK/CAZ + 1.5e0 897 OneEighty: 898 // BACKWARD RECURRENCE LOOP FOR MILLER ALGORITHM. 899 K = int(float32(FK)) 900 FK = float64(K) 901 FKS = FK * FK 902 P1R = CZEROR 903 P1I = CZEROI 904 P2R = TOL 905 P2I = CZEROI 906 CSR = P2R 907 CSI = P2I 908 for I = 1; I <= K; I++ { 909 A1 = FKS - FK 910 AK = (FKS + FK) / (A1 + FHS) 911 RAK = 2.0e0 / (FK + CONER) 912 CBR = (FK + ZR) * RAK 913 CBI = ZI * RAK 914 PTR = P2R 915 PTI = P2I 916 P2R = (PTR*CBR - PTI*CBI - P1R) * AK 917 P2I = (PTI*CBR + PTR*CBI - P1I) * AK 918 P1R = PTR 919 P1I = PTI 920 CSR = CSR + P2R 921 CSI = CSI + P2I 922 FKS = A1 - FK + CONER 923 FK = FK - CONER 924 } 925 // COMPUTE (P2/CS)=(P2/CABS(CS))*(CONJG(CS)/CABS(CS)) FOR BETTER SCALING. 926 TM = cmplx.Abs(complex(CSR, CSI)) 927 PTR = 1.0e0 / TM 928 S1R = P2R * PTR 929 S1I = P2I * PTR 930 CSR = CSR * PTR 931 CSI = -CSI * PTR 932 tmp = complex(COEFR, COEFI) * complex(S1R, S1I) 933 STR = real(tmp) 934 STI = imag(tmp) 935 tmp = complex(STR, STI) * complex(CSR, CSI) 936 S1R = real(tmp) 937 S1I = imag(tmp) 938 if INU > 0 || N > 1 { 939 goto TwoHundred 940 } 941 ZDR = ZR 942 ZDI = ZI 943 if IFLAG == 1 { 944 goto TwoSeventy 945 } 946 goto TwoFourty 947 TwoHundred: 948 // COMPUTE P1/P2=(P1/CABS(P2)*CONJG(P2)/CABS(P2) FOR SCALING. 949 TM = cmplx.Abs(complex(P2R, P2I)) 950 PTR = 1.0e0 / TM 951 P1R = P1R * PTR 952 P1I = P1I * PTR 953 P2R = P2R * PTR 954 P2I = -P2I * PTR 955 tmp = complex(P1R, P1I) * complex(P2R, P2I) 956 PTR = real(tmp) 957 PTI = imag(tmp) 958 STR = DNU + 0.5e0 - PTR 959 STI = -PTI 960 tmp = complex(STR, STI) / complex(ZR, ZI) 961 STR = real(tmp) 962 STI = imag(tmp) 963 STR = STR + 1.0e0 964 tmp = complex(STR, STI) * complex(S1R, S1I) 965 S2R = real(tmp) 966 S2I = imag(tmp) 967 968 // FORWARD RECURSION ON THE THREE TERM RECURSION WITH RELATION WITH 969 // SCALING NEAR EXPONENT EXTREMES ON KFLAG=1 OR KFLAG=3 970 TwoTen: 971 STR = DNU + 1.0e0 972 CKR = STR * RZR 973 CKI = STR * RZI 974 if N == 1 { 975 INU = INU - 1 976 } 977 if INU > 0 { 978 goto TwoTwenty 979 } 980 if N > 1 { 981 goto TwoFifteen 982 } 983 S1R = S2R 984 S1I = S2I 985 TwoFifteen: 986 ZDR = ZR 987 ZDI = ZI 988 if IFLAG == 1 { 989 goto TwoSeventy 990 } 991 goto TwoFourty 992 TwoTwenty: 993 INUB = 1 994 if IFLAG == 1 { 995 goto TwoSixtyOne 996 } 997 TwoTwentyFive: 998 P1R = CSRR[KFLAG] 999 ASCLE = BRY[KFLAG] 1000 for I = INUB; I <= INU; I++ { 1001 STR = S2R 1002 STI = S2I 1003 S2R = CKR*STR - CKI*STI + S1R 1004 S2I = CKR*STI + CKI*STR + S1I 1005 S1R = STR 1006 S1I = STI 1007 CKR = CKR + RZR 1008 CKI = CKI + RZI 1009 if KFLAG >= 3 { 1010 continue 1011 } 1012 P2R = S2R * P1R 1013 P2I = S2I * P1R 1014 STR = math.Abs(P2R) 1015 STI = math.Abs(P2I) 1016 P2M = math.Max(STR, STI) 1017 if P2M <= ASCLE { 1018 continue 1019 } 1020 KFLAG = KFLAG + 1 1021 ASCLE = BRY[KFLAG] 1022 S1R = S1R * P1R 1023 S1I = S1I * P1R 1024 S2R = P2R 1025 S2I = P2I 1026 STR = CSSR[KFLAG] 1027 S1R = S1R * STR 1028 S1I = S1I * STR 1029 S2R = S2R * STR 1030 S2I = S2I * STR 1031 P1R = CSRR[KFLAG] 1032 } 1033 if N != 1 { 1034 goto TwoFourty 1035 } 1036 S1R = S2R 1037 S1I = S2I 1038 TwoFourty: 1039 STR = CSRR[KFLAG] 1040 YR[1] = S1R * STR 1041 YI[1] = S1I * STR 1042 if N == 1 { 1043 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1044 } 1045 YR[2] = S2R * STR 1046 YI[2] = S2I * STR 1047 if N == 2 { 1048 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1049 } 1050 KK = 2 1051 TwoFifty: 1052 KK = KK + 1 1053 if KK > N { 1054 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1055 } 1056 P1R = CSRR[KFLAG] 1057 ASCLE = BRY[KFLAG] 1058 for I = KK; I <= N; I++ { 1059 P2R = S2R 1060 P2I = S2I 1061 S2R = CKR*P2R - CKI*P2I + S1R 1062 S2I = CKI*P2R + CKR*P2I + S1I 1063 S1R = P2R 1064 S1I = P2I 1065 CKR = CKR + RZR 1066 CKI = CKI + RZI 1067 P2R = S2R * P1R 1068 P2I = S2I * P1R 1069 YR[I] = P2R 1070 YI[I] = P2I 1071 if KFLAG >= 3 { 1072 continue 1073 } 1074 STR = math.Abs(P2R) 1075 STI = math.Abs(P2I) 1076 P2M = math.Max(STR, STI) 1077 if P2M <= ASCLE { 1078 continue 1079 } 1080 KFLAG = KFLAG + 1 1081 ASCLE = BRY[KFLAG] 1082 S1R = S1R * P1R 1083 S1I = S1I * P1R 1084 S2R = P2R 1085 S2I = P2I 1086 STR = CSSR[KFLAG] 1087 S1R = S1R * STR 1088 S1I = S1I * STR 1089 S2R = S2R * STR 1090 S2I = S2I * STR 1091 P1R = CSRR[KFLAG] 1092 } 1093 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1094 1095 // IFLAG=1 CASES, FORWARD RECURRENCE ON SCALED VALUES ON UNDERFLOW. 1096 TwoSixtyOne: 1097 HELIM = 0.5e0 * ELIM 1098 ELM = math.Exp(-ELIM) 1099 CELMR = ELM 1100 ASCLE = BRY[1] 1101 ZDR = ZR 1102 ZDI = ZI 1103 IC = -1 1104 J = 2 1105 for I = 1; I <= INU; I++ { 1106 STR = S2R 1107 STI = S2I 1108 S2R = STR*CKR - STI*CKI + S1R 1109 S2I = STI*CKR + STR*CKI + S1I 1110 S1R = STR 1111 S1I = STI 1112 CKR = CKR + RZR 1113 CKI = CKI + RZI 1114 AS = cmplx.Abs(complex(S2R, S2I)) 1115 ALAS = math.Log(AS) 1116 P2R = -ZDR + ALAS 1117 if P2R < (-ELIM) { 1118 goto TwoSixtyThree 1119 } 1120 tmp = cmplx.Log(complex(S2R, S2I)) 1121 STR = real(tmp) 1122 STI = imag(tmp) 1123 P2R = -ZDR + STR 1124 P2I = -ZDI + STI 1125 P2M = math.Exp(P2R) / TOL 1126 // sin, cos = math.Sincos(P2I) 1127 P1R = P2M * math.Cos(P2I) 1128 P1I = P2M * math.Sin(P2I) 1129 p = complex(P1R, P1I) 1130 NW = Zuchk(p, ASCLE, TOL) 1131 if NW != 0 { 1132 goto TwoSixtyThree 1133 } 1134 J = 3 - J 1135 CYR[J] = P1R 1136 CYI[J] = P1I 1137 if IC == (I - 1) { 1138 goto TwoSixtyFour 1139 } 1140 IC = I 1141 continue 1142 TwoSixtyThree: 1143 if ALAS < HELIM { 1144 continue 1145 } 1146 ZDR = ZDR - ELIM 1147 S1R = S1R * CELMR 1148 S1I = S1I * CELMR 1149 S2R = S2R * CELMR 1150 S2I = S2I * CELMR 1151 } 1152 if N != 1 { 1153 goto TwoSeventy 1154 } 1155 S1R = S2R 1156 S1I = S2I 1157 goto TwoSeventy 1158 TwoSixtyFour: 1159 KFLAG = 1 1160 INUB = I + 1 1161 S2R = CYR[J] 1162 S2I = CYI[J] 1163 J = 3 - J 1164 S1R = CYR[J] 1165 S1I = CYI[J] 1166 if INUB <= INU { 1167 goto TwoTwentyFive 1168 } 1169 if N != 1 { 1170 goto TwoFourty 1171 } 1172 S1R = S2R 1173 S1I = S2I 1174 goto TwoFourty 1175 TwoSeventy: 1176 YR[1] = S1R 1177 YI[1] = S1I 1178 if N == 1 { 1179 goto TwoEighty 1180 } 1181 YR[2] = S2R 1182 YI[2] = S2I 1183 TwoEighty: 1184 ASCLE = BRY[1] 1185 _, _, FNU, N, YR, YI, NZ, RZR, RZI, _, TOL, ELIM = Zkscl(ZDR, ZDI, FNU, N, YR, YI, RZR, RZI, ASCLE, TOL, ELIM) 1186 INU = N - NZ 1187 if INU <= 0 { 1188 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1189 } 1190 KK = NZ + 1 1191 S1R = YR[KK] 1192 S1I = YI[KK] 1193 YR[KK] = S1R * CSRR[1] 1194 YI[KK] = S1I * CSRR[1] 1195 if INU == 1 { 1196 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1197 } 1198 KK = NZ + 2 1199 S2R = YR[KK] 1200 S2I = YI[KK] 1201 YR[KK] = S2R * CSRR[1] 1202 YI[KK] = S2I * CSRR[1] 1203 if INU == 2 { 1204 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1205 } 1206 T2 = FNU + float64(float32(KK-1)) 1207 CKR = T2 * RZR 1208 CKI = T2 * RZI 1209 KFLAG = 1 1210 goto TwoFifty 1211 TwoNinety: 1212 1213 // SCALE BY math.Exp(Z), IFLAG = 1 CASES. 1214 1215 IFLAG = 1 1216 KFLAG = 2 1217 goto OneTwenty 1218 1219 // FNU=HALF ODD INTEGER CASE, DNU=-0.5 1220 ThreeHundred: 1221 S1R = COEFR 1222 S1I = COEFI 1223 S2R = COEFR 1224 S2I = COEFI 1225 goto TwoTen 1226 1227 ThreeTen: 1228 NZ = -2 1229 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM 1230 } 1231 1232 // SET K FUNCTIONS TO ZERO ON UNDERFLOW, CONTINUE RECURRENCE 1233 // ON SCALED FUNCTIONS UNTIL TWO MEMBERS COME ON SCALE, THEN 1234 // return WITH MIN(NZ+2,N) VALUES SCALED BY 1/TOL. 1235 func Zkscl(ZRR, ZRI, FNU float64, N int, YR, YI []float64, RZR, RZI, ASCLE, TOL, ELIM float64) ( 1236 ZRRout, ZRIout, FNUout float64, Nout int, YRout, YIout []float64, NZ int, RZRout, RZIout, ASCLEout, TOLout, ELIMout float64) { 1237 var ACS, AS, CKI, CKR, CSI, CSR, FN, STR, S1I, S1R, S2I, 1238 S2R, ZEROI, ZEROR, ZDR, ZDI, CELMR, ELM, HELIM, ALAS float64 1239 1240 var I, IC, KK, NN, NW int 1241 var tmp, c complex128 1242 var CYR, CYI [3]float64 1243 var sin, cos float64 1244 1245 // DIMENSION YR(N), YI(N), CYR(2), CYI(2) 1246 ZEROR = 0 1247 ZEROI = 0 1248 IC = 0 1249 NN = min(2, N) 1250 for I = 1; I <= NN; I++ { 1251 S1R = YR[I] 1252 S1I = YI[I] 1253 CYR[I] = S1R 1254 CYI[I] = S1I 1255 AS = cmplx.Abs(complex(S1R, S1I)) 1256 ACS = -ZRR + math.Log(AS) 1257 NZ = NZ + 1 1258 YR[I] = ZEROR 1259 YI[I] = ZEROI 1260 if ACS < (-ELIM) { 1261 continue 1262 } 1263 1264 tmp = cmplx.Log(complex(S1R, S1I)) 1265 CSR = real(tmp) 1266 CSI = imag(tmp) 1267 CSR = CSR - ZRR 1268 CSI = CSI - ZRI 1269 STR = math.Exp(CSR) / TOL 1270 // sin, cos = math.Sincos(CSI) 1271 CSR = STR * math.Cos(CSI) 1272 CSI = STR * math.Sin(CSI) 1273 c = complex(CSR, CSI) 1274 NW = Zuchk(c, ASCLE, TOL) 1275 if NW != 0 { 1276 continue 1277 } 1278 YR[I] = CSR 1279 YI[I] = CSI 1280 IC = I 1281 NZ = NZ - 1 1282 } 1283 if N == 1 { 1284 return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM 1285 } 1286 if IC > 1 { 1287 goto Twenty 1288 } 1289 YR[1] = ZEROR 1290 YI[1] = ZEROI 1291 NZ = 2 1292 Twenty: 1293 if N == 2 { 1294 return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM 1295 } 1296 if NZ == 0 { 1297 return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM 1298 } 1299 FN = FNU + 1.0e0 1300 CKR = FN * RZR 1301 CKI = FN * RZI 1302 S1R = CYR[1] 1303 S1I = CYI[1] 1304 S2R = CYR[2] 1305 S2I = CYI[2] 1306 HELIM = 0.5e0 * ELIM 1307 ELM = math.Exp(-ELIM) 1308 CELMR = ELM 1309 ZDR = ZRR 1310 ZDI = ZRI 1311 1312 // FIND TWO CONSECUTIVE Y VALUES ON SCALE. SCALE RECURRENCE IF 1313 // S2 GETS LARGER THAN EXP(ELIM/2) 1314 for I = 3; I <= N; I++ { 1315 KK = I 1316 CSR = S2R 1317 CSI = S2I 1318 S2R = CKR*CSR - CKI*CSI + S1R 1319 S2I = CKI*CSR + CKR*CSI + S1I 1320 S1R = CSR 1321 S1I = CSI 1322 CKR = CKR + RZR 1323 CKI = CKI + RZI 1324 AS = cmplx.Abs(complex(S2R, S2I)) 1325 ALAS = math.Log(AS) 1326 ACS = -ZDR + ALAS 1327 NZ = NZ + 1 1328 YR[I] = ZEROR 1329 YI[I] = ZEROI 1330 if ACS < (-ELIM) { 1331 goto TwentyFive 1332 } 1333 tmp = cmplx.Log(complex(S2R, S2I)) 1334 CSR = real(tmp) 1335 CSI = imag(tmp) 1336 CSR = CSR - ZDR 1337 CSI = CSI - ZDI 1338 STR = math.Exp(CSR) / TOL 1339 sin, cos = math.Sincos(CSI) 1340 CSR = STR * cos 1341 CSI = STR * sin 1342 c = complex(CSR, CSI) 1343 NW = Zuchk(c, ASCLE, TOL) 1344 if NW != 0 { 1345 goto TwentyFive 1346 } 1347 YR[I] = CSR 1348 YI[I] = CSI 1349 NZ = NZ - 1 1350 if IC == KK-1 { 1351 goto Forty 1352 } 1353 IC = KK 1354 continue 1355 TwentyFive: 1356 if ALAS < HELIM { 1357 continue 1358 } 1359 ZDR = ZDR - ELIM 1360 S1R = S1R * CELMR 1361 S1I = S1I * CELMR 1362 S2R = S2R * CELMR 1363 S2I = S2I * CELMR 1364 } 1365 NZ = N 1366 if IC == N { 1367 NZ = N - 1 1368 } 1369 goto FourtyFive 1370 Forty: 1371 NZ = KK - 2 1372 FourtyFive: 1373 for I = 1; I <= NZ; I++ { 1374 YR[I] = ZEROR 1375 YI[I] = ZEROI 1376 } 1377 return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM 1378 } 1379 1380 // Zuchk tests whether the magnitude of the real or imaginary part would 1381 // underflow when y is scaled by tol. 1382 // 1383 // y enters as a scaled quantity whose magnitude is greater than 1384 // 1e3 + 3*dmach(1)/tol 1385 // y is accepted if the underflow is at least one precision below the magnitude 1386 // of the largest component. Otherwise an underflow is assumed as the phase angle 1387 // does not have sufficient accuracy. 1388 func Zuchk(y complex128, scale, tol float64) int { 1389 absR := math.Abs(real(y)) 1390 absI := math.Abs(imag(y)) 1391 minAbs := math.Min(absR, absI) 1392 if minAbs > scale { 1393 return 0 1394 } 1395 maxAbs := math.Max(absR, absI) 1396 minAbs /= tol 1397 if maxAbs < minAbs { 1398 return 1 1399 } 1400 return 0 1401 } 1402 1403 // ZACAI APPLIES THE ANALYTIC CONTINUATION FORMULA 1404 // 1405 // K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN) 1406 // MP=PI*MR*CMPLX(0.0,1.0) 1407 // 1408 // TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT 1409 // HALF Z PLANE FOR USE WITH ZAIRY WHERE FNU=1/3 OR 2/3 AND N=1. 1410 // ZACAI IS THE SAME AS ZACON WITH THE PARTS FOR LARGER ORDERS AND 1411 // RECURRENCE REMOVED. A RECURSIVE CALL TO ZACON CAN RESULT if ZACON 1412 // IS CALLED FROM ZAIRY. 1413 func Zacai(ZR, ZI, FNU float64, KODE, MR, N int, YR, YI []float64, RL, TOL, ELIM, ALIM float64) ( 1414 ZRout, ZIout, FNUout float64, KODEout, MRout, Nout int, YRout, YIout []float64, NZ int, RLout, TOLout, ELIMout, ALIMout float64) { 1415 var ARG, ASCLE, AZ, CSGNR, CSGNI, CSPNR, 1416 CSPNI, C1R, C1I, C2R, C2I, DFNU, FMR, PI, 1417 SGN, YY, ZNR, ZNI float64 1418 var INU, IUF, NN, NW int 1419 var zn, c1, c2, z complex128 1420 var y []complex128 1421 //var sin, cos float64 1422 1423 CYR := []float64{math.NaN(), 0, 0} 1424 CYI := []float64{math.NaN(), 0, 0} 1425 1426 PI = math.Pi 1427 ZNR = -ZR 1428 ZNI = -ZI 1429 AZ = cmplx.Abs(complex(ZR, ZI)) 1430 NN = N 1431 DFNU = FNU + float64(float32(N-1)) 1432 if AZ <= 2.0e0 { 1433 goto Ten 1434 } 1435 if AZ*AZ*0.25 > DFNU+1.0e0 { 1436 goto Twenty 1437 } 1438 Ten: 1439 // POWER SERIES FOR THE I FUNCTION. 1440 z = complex(ZNR, ZNI) 1441 y = make([]complex128, len(YR)) 1442 for i, v := range YR { 1443 y[i] = complex(v, YI[i]) 1444 } 1445 Zseri(z, FNU, KODE, NN, y[1:], TOL, ELIM, ALIM) 1446 for i, v := range y { 1447 YR[i] = real(v) 1448 YI[i] = imag(v) 1449 } 1450 goto Forty 1451 Twenty: 1452 if AZ < RL { 1453 goto Thirty 1454 } 1455 // ASYMPTOTIC EXPANSION FOR LARGE Z FOR THE I FUNCTION. 1456 ZNR, ZNI, FNU, KODE, _, YR, YI, NW, RL, TOL, ELIM, ALIM = Zasyi(ZNR, ZNI, FNU, KODE, NN, YR, YI, RL, TOL, ELIM, ALIM) 1457 if NW < 0 { 1458 goto Eighty 1459 } 1460 goto Forty 1461 Thirty: 1462 // MILLER ALGORITHM NORMALIZED BY THE SERIES FOR THE I FUNCTION 1463 ZNR, ZNI, FNU, KODE, _, YR, YI, NW, TOL = Zmlri(ZNR, ZNI, FNU, KODE, NN, YR, YI, TOL) 1464 if NW < 0 { 1465 goto Eighty 1466 } 1467 Forty: 1468 // ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION. 1469 ZNR, ZNI, FNU, KODE, _, CYR, CYI, NW, TOL, ELIM, ALIM = Zbknu(ZNR, ZNI, FNU, KODE, 1, CYR, CYI, TOL, ELIM, ALIM) 1470 if NW != 0 { 1471 goto Eighty 1472 } 1473 FMR = float64(float32(MR)) 1474 SGN = -math.Copysign(PI, FMR) 1475 CSGNR = 0.0e0 1476 CSGNI = SGN 1477 if KODE == 1 { 1478 goto Fifty 1479 } 1480 YY = -ZNI 1481 //sin, cos = math.Sincos(YY) 1482 CSGNR = -CSGNI * math.Sin(YY) 1483 CSGNI = CSGNI * math.Cos(YY) 1484 Fifty: 1485 // CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE 1486 // WHEN FNU IS LARGE 1487 INU = int(float32(FNU)) 1488 ARG = (FNU - float64(float32(INU))) * SGN 1489 //sin, cos = math.Sincos(ARG) 1490 CSPNR = math.Cos(ARG) 1491 CSPNI = math.Sin(ARG) 1492 if INU%2 == 0 { 1493 goto Sixty 1494 } 1495 CSPNR = -CSPNR 1496 CSPNI = -CSPNI 1497 Sixty: 1498 C1R = CYR[1] 1499 C1I = CYI[1] 1500 C2R = YR[1] 1501 C2I = YI[1] 1502 if KODE == 1 { 1503 goto Seventy 1504 } 1505 IUF = 0 1506 ASCLE = 1.0e+3 * dmach[1] / TOL 1507 zn = complex(ZNR, ZNI) 1508 c1 = complex(C1R, C1I) 1509 c2 = complex(C2R, C2I) 1510 c1, c2, NW, _ = Zs1s2(zn, c1, c2, ASCLE, ALIM, IUF) 1511 C1R = real(c1) 1512 C1I = imag(c1) 1513 C2R = real(c2) 1514 C2I = imag(c2) 1515 NZ = NZ + NW 1516 Seventy: 1517 YR[1] = CSPNR*C1R - CSPNI*C1I + CSGNR*C2R - CSGNI*C2I 1518 YI[1] = CSPNR*C1I + CSPNI*C1R + CSGNR*C2I + CSGNI*C2R 1519 return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1520 Eighty: 1521 NZ = -1 1522 if NW == -2 { 1523 NZ = -2 1524 } 1525 return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1526 } 1527 1528 // ZASYI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z)>=0.0 BY 1529 // MEANS OF THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z) IN THE 1530 // REGION CABS(Z)>MAX(RL,FNU*FNU/2). NZ=0 IS A NORMAL return. 1531 // NZ<0 INDICATES AN OVERFLOW ON KODE=1. 1532 func Zasyi(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, RL, TOL, ELIM, ALIM float64) ( 1533 ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, RLout, TOLout, ELIMout, ALIMout float64) { 1534 var AA, AEZ, AK, AK1I, AK1R, ARG, ARM, ATOL, 1535 AZ, BB, BK, CKI, CKR, CONEI, CONER, CS1I, CS1R, CS2I, CS2R, CZI, 1536 CZR, DFNU, DKI, DKR, DNU2, EZI, EZR, FDN, PI, P1I, 1537 P1R, RAZ, RTPI, RTR1, RZI, RZR, S, SGN, SQK, STI, STR, S2I, 1538 S2R, TZI, TZR, ZEROI, ZEROR float64 1539 1540 var I, IB, IL, INU, J, JL, K, KODED, M, NN int 1541 var tmp complex128 1542 // var sin, cos float64 1543 1544 PI = math.Pi 1545 RTPI = 0.159154943091895336e0 1546 ZEROR = 0 1547 ZEROI = 0 1548 CONER = 1 1549 CONEI = 0 1550 1551 AZ = cmplx.Abs(complex(ZR, ZI)) 1552 ARM = 1.0e3 * dmach[1] 1553 RTR1 = math.Sqrt(ARM) 1554 IL = min(2, N) 1555 DFNU = FNU + float64(float32(N-IL)) 1556 1557 // OVERFLOW TEST 1558 RAZ = 1.0e0 / AZ 1559 STR = ZR * RAZ 1560 STI = -ZI * RAZ 1561 AK1R = RTPI * STR * RAZ 1562 AK1I = RTPI * STI * RAZ 1563 tmp = cmplx.Sqrt(complex(AK1R, AK1I)) 1564 AK1R = real(tmp) 1565 AK1I = imag(tmp) 1566 CZR = ZR 1567 CZI = ZI 1568 if KODE != 2 { 1569 goto Ten 1570 } 1571 CZR = ZEROR 1572 CZI = ZI 1573 Ten: 1574 if math.Abs(CZR) > ELIM { 1575 goto OneHundred 1576 } 1577 DNU2 = DFNU + DFNU 1578 KODED = 1 1579 if (math.Abs(CZR) > ALIM) && (N > 2) { 1580 goto Twenty 1581 } 1582 KODED = 0 1583 tmp = cmplx.Exp(complex(CZR, CZI)) 1584 STR = real(tmp) 1585 STI = imag(tmp) 1586 tmp = complex(AK1R, AK1I) * complex(STR, STI) 1587 AK1R = real(tmp) 1588 AK1I = imag(tmp) 1589 Twenty: 1590 FDN = 0.0e0 1591 if DNU2 > RTR1 { 1592 FDN = DNU2 * DNU2 1593 } 1594 EZR = ZR * 8.0e0 1595 EZI = ZI * 8.0e0 1596 1597 // WHEN Z IS IMAGINARY, THE ERROR TEST MUST BE MADE RELATIVE TO THE 1598 // FIRST RECIPROCAL POWER SINCE THIS IS THE LEADING TERM OF THE 1599 // EXPANSION FOR THE IMAGINARY PART. 1600 AEZ = 8.0e0 * AZ 1601 S = TOL / AEZ 1602 JL = int(float32(RL+RL)) + 2 1603 P1R = ZEROR 1604 P1I = ZEROI 1605 if ZI == 0.0e0 { 1606 goto Thirty 1607 } 1608 1609 // CALCULATE EXP(PI*(0.5+FNU+N-IL)*I) TO MINIMIZE LOSSES OF 1610 // SIGNIFICANCE WHEN FNU OR N IS LARGE 1611 INU = int(float32(FNU)) 1612 ARG = (FNU - float64(float32(INU))) * PI 1613 INU = INU + N - IL 1614 //sin, cos = math.Sincos(ARG) 1615 AK = -math.Sin(ARG) 1616 BK = math.Cos(ARG) 1617 if ZI < 0.0e0 { 1618 BK = -BK 1619 } 1620 P1R = AK 1621 P1I = BK 1622 if INU%2 == 0 { 1623 goto Thirty 1624 } 1625 P1R = -P1R 1626 P1I = -P1I 1627 Thirty: 1628 for K = 1; K <= IL; K++ { 1629 SQK = FDN - 1.0e0 1630 ATOL = S * math.Abs(SQK) 1631 SGN = 1.0e0 1632 CS1R = CONER 1633 CS1I = CONEI 1634 CS2R = CONER 1635 CS2I = CONEI 1636 CKR = CONER 1637 CKI = CONEI 1638 AK = 0.0e0 1639 AA = 1.0e0 1640 BB = AEZ 1641 DKR = EZR 1642 DKI = EZI 1643 // TODO(btracey): This loop is executed tens of thousands of times. Why? 1644 // is that really necessary? 1645 for J = 1; J <= JL; J++ { 1646 tmp = complex(CKR, CKI) / complex(DKR, DKI) 1647 STR = real(tmp) 1648 STI = imag(tmp) 1649 CKR = STR * SQK 1650 CKI = STI * SQK 1651 CS2R = CS2R + CKR 1652 CS2I = CS2I + CKI 1653 SGN = -SGN 1654 CS1R = CS1R + CKR*SGN 1655 CS1I = CS1I + CKI*SGN 1656 DKR = DKR + EZR 1657 DKI = DKI + EZI 1658 AA = AA * math.Abs(SQK) / BB 1659 BB = BB + AEZ 1660 AK = AK + 8.0e0 1661 SQK = SQK - AK 1662 if AA <= ATOL { 1663 goto Fifty 1664 } 1665 } 1666 goto OneTen 1667 Fifty: 1668 S2R = CS1R 1669 S2I = CS1I 1670 if ZR+ZR >= ELIM { 1671 goto Sixty 1672 } 1673 TZR = ZR + ZR 1674 TZI = ZI + ZI 1675 tmp = cmplx.Exp(complex(-TZR, -TZI)) 1676 STR = real(tmp) 1677 STI = imag(tmp) 1678 tmp = complex(STR, STI) * complex(P1R, P1I) 1679 STR = real(tmp) 1680 STI = imag(tmp) 1681 tmp = complex(STR, STI) * complex(CS2R, CS2I) 1682 STR = real(tmp) 1683 STI = imag(tmp) 1684 S2R = S2R + STR 1685 S2I = S2I + STI 1686 Sixty: 1687 FDN = FDN + 8.0e0*DFNU + 4.0e0 1688 P1R = -P1R 1689 P1I = -P1I 1690 M = N - IL + K 1691 YR[M] = S2R*AK1R - S2I*AK1I 1692 YI[M] = S2R*AK1I + S2I*AK1R 1693 } 1694 if N <= 2 { 1695 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1696 } 1697 NN = N 1698 K = NN - 2 1699 AK = float64(float32(K)) 1700 STR = ZR * RAZ 1701 STI = -ZI * RAZ 1702 RZR = (STR + STR) * RAZ 1703 RZI = (STI + STI) * RAZ 1704 IB = 3 1705 for I = IB; I <= NN; I++ { 1706 YR[K] = (AK+FNU)*(RZR*YR[K+1]-RZI*YI[K+1]) + YR[K+2] 1707 YI[K] = (AK+FNU)*(RZR*YI[K+1]+RZI*YR[K+1]) + YI[K+2] 1708 AK = AK - 1.0e0 1709 K = K - 1 1710 } 1711 if KODED == 0 { 1712 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1713 } 1714 tmp = cmplx.Exp(complex(CZR, CZI)) 1715 CKR = real(tmp) 1716 CKI = imag(tmp) 1717 for I = 1; I <= NN; I++ { 1718 STR = YR[I]*CKR - YI[I]*CKI 1719 YI[I] = YR[I]*CKI + YI[I]*CKR 1720 YR[I] = STR 1721 } 1722 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1723 OneHundred: 1724 NZ = -1 1725 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1726 OneTen: 1727 NZ = -2 1728 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1729 } 1730 1731 // ZMLRI COMPUTES THE I BESSEL FUNCTION FOR RE(Z)>=0.0 BY THE 1732 // MILLER ALGORITHM NORMALIZED BY A NEUMANN SERIES. 1733 func Zmlri(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, TOL float64) ( 1734 ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, TOLout float64) { 1735 var ACK, AK, AP, AT, AZ, BK, CKI, CKR, CNORMI, 1736 CNORMR, CONEI, CONER, FKAP, FKK, FLAM, FNF, PTI, PTR, P1I, 1737 P1R, P2I, P2R, RAZ, RHO, RHO2, RZI, RZR, SCLE, STI, STR, SUMI, 1738 SUMR, TFNF, TST, ZEROI, ZEROR float64 1739 var I, IAZ, IDUM, IFNU, INU, ITIME, K, KK, KM, M int 1740 var tmp complex128 1741 ZEROR = 0 1742 ZEROI = 0 1743 CONER = 1 1744 CONEI = 0 1745 1746 SCLE = dmach[1] / TOL 1747 AZ = cmplx.Abs(complex(ZR, ZI)) 1748 IAZ = int(float32(AZ)) 1749 IFNU = int(float32(FNU)) 1750 INU = IFNU + N - 1 1751 AT = float64(float32(IAZ)) + 1.0e0 1752 RAZ = 1.0e0 / AZ 1753 STR = ZR * RAZ 1754 STI = -ZI * RAZ 1755 CKR = STR * AT * RAZ 1756 CKI = STI * AT * RAZ 1757 RZR = (STR + STR) * RAZ 1758 RZI = (STI + STI) * RAZ 1759 P1R = ZEROR 1760 P1I = ZEROI 1761 P2R = CONER 1762 P2I = CONEI 1763 ACK = (AT + 1.0e0) * RAZ 1764 RHO = ACK + math.Sqrt(ACK*ACK-1.0e0) 1765 RHO2 = RHO * RHO 1766 TST = (RHO2 + RHO2) / ((RHO2 - 1.0e0) * (RHO - 1.0e0)) 1767 TST = TST / TOL 1768 1769 // COMPUTE RELATIVE TRUNCATION ERROR INDEX FOR SERIES. 1770 //fmt.Println("before loop", P2R, P2I, CKR, CKI, RZR, RZI, TST, AK) 1771 AK = AT 1772 for I = 1; I <= 80; I++ { 1773 PTR = P2R 1774 PTI = P2I 1775 P2R = P1R - (CKR*PTR - CKI*PTI) 1776 P2I = P1I - (CKI*PTR + CKR*PTI) 1777 P1R = PTR 1778 P1I = PTI 1779 CKR = CKR + RZR 1780 CKI = CKI + RZI 1781 AP = cmplx.Abs(complex(P2R, P2I)) 1782 if AP > TST*AK*AK { 1783 goto Twenty 1784 } 1785 AK = AK + 1.0e0 1786 } 1787 goto OneTen 1788 Twenty: 1789 I = I + 1 1790 K = 0 1791 if INU < IAZ { 1792 goto Forty 1793 } 1794 // COMPUTE RELATIVE TRUNCATION ERROR FOR RATIOS. 1795 P1R = ZEROR 1796 P1I = ZEROI 1797 P2R = CONER 1798 P2I = CONEI 1799 AT = float64(float32(INU)) + 1.0e0 1800 STR = ZR * RAZ 1801 STI = -ZI * RAZ 1802 CKR = STR * AT * RAZ 1803 CKI = STI * AT * RAZ 1804 ACK = AT * RAZ 1805 TST = math.Sqrt(ACK / TOL) 1806 ITIME = 1 1807 for K = 1; K <= 80; K++ { 1808 PTR = P2R 1809 PTI = P2I 1810 P2R = P1R - (CKR*PTR - CKI*PTI) 1811 P2I = P1I - (CKR*PTI + CKI*PTR) 1812 P1R = PTR 1813 P1I = PTI 1814 CKR = CKR + RZR 1815 CKI = CKI + RZI 1816 AP = cmplx.Abs(complex(P2R, P2I)) 1817 if AP < TST { 1818 continue 1819 } 1820 if ITIME == 2 { 1821 goto Forty 1822 } 1823 ACK = cmplx.Abs(complex(CKR, CKI)) 1824 FLAM = ACK + math.Sqrt(ACK*ACK-1.0e0) 1825 FKAP = AP / cmplx.Abs(complex(P1R, P1I)) 1826 RHO = math.Min(FLAM, FKAP) 1827 TST = TST * math.Sqrt(RHO/(RHO*RHO-1.0e0)) 1828 ITIME = 2 1829 } 1830 goto OneTen 1831 Forty: 1832 // BACKWARD RECURRENCE AND SUM NORMALIZING RELATION. 1833 K = K + 1 1834 KK = max(I+IAZ, K+INU) 1835 FKK = float64(float32(KK)) 1836 P1R = ZEROR 1837 P1I = ZEROI 1838 1839 // SCALE P2 AND SUM BY SCLE. 1840 P2R = SCLE 1841 P2I = ZEROI 1842 FNF = FNU - float64(float32(IFNU)) 1843 TFNF = FNF + FNF 1844 BK = dgamln(FKK+TFNF+1.0e0, IDUM) - dgamln(FKK+1.0e0, IDUM) - dgamln(TFNF+1.0e0, IDUM) 1845 BK = math.Exp(BK) 1846 SUMR = ZEROR 1847 SUMI = ZEROI 1848 KM = KK - INU 1849 for I = 1; I <= KM; I++ { 1850 PTR = P2R 1851 PTI = P2I 1852 P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) 1853 P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) 1854 P1R = PTR 1855 P1I = PTI 1856 AK = 1.0e0 - TFNF/(FKK+TFNF) 1857 ACK = BK * AK 1858 SUMR = SUMR + (ACK+BK)*P1R 1859 SUMI = SUMI + (ACK+BK)*P1I 1860 BK = ACK 1861 FKK = FKK - 1.0e0 1862 } 1863 YR[N] = P2R 1864 YI[N] = P2I 1865 if N == 1 { 1866 goto Seventy 1867 } 1868 for I = 2; I <= N; I++ { 1869 PTR = P2R 1870 PTI = P2I 1871 P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) 1872 P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) 1873 P1R = PTR 1874 P1I = PTI 1875 AK = 1.0e0 - TFNF/(FKK+TFNF) 1876 ACK = BK * AK 1877 SUMR = SUMR + (ACK+BK)*P1R 1878 SUMI = SUMI + (ACK+BK)*P1I 1879 BK = ACK 1880 FKK = FKK - 1.0e0 1881 M = N - I + 1 1882 YR[M] = P2R 1883 YI[M] = P2I 1884 } 1885 Seventy: 1886 if IFNU <= 0 { 1887 goto Ninety 1888 } 1889 for I = 1; I <= IFNU; I++ { 1890 PTR = P2R 1891 PTI = P2I 1892 P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) 1893 P2I = P1I + (FKK+FNF)*(RZR*PTI+RZI*PTR) 1894 P1R = PTR 1895 P1I = PTI 1896 AK = 1.0e0 - TFNF/(FKK+TFNF) 1897 ACK = BK * AK 1898 SUMR = SUMR + (ACK+BK)*P1R 1899 SUMI = SUMI + (ACK+BK)*P1I 1900 BK = ACK 1901 FKK = FKK - 1.0e0 1902 } 1903 Ninety: 1904 PTR = ZR 1905 PTI = ZI 1906 if KODE == 2 { 1907 PTR = ZEROR 1908 } 1909 tmp = cmplx.Log(complex(RZR, RZI)) 1910 STR = real(tmp) 1911 STI = imag(tmp) 1912 P1R = -FNF*STR + PTR 1913 P1I = -FNF*STI + PTI 1914 AP = dgamln(1.0e0+FNF, IDUM) 1915 PTR = P1R - AP 1916 PTI = P1I 1917 1918 // THE DIVISION CEXP(PT)/(SUM+P2) IS ALTERED TO AVOID OVERFLOW 1919 // IN THE DENOMINATOR BY SQUARING LARGE QUANTITIES. 1920 P2R = P2R + SUMR 1921 P2I = P2I + SUMI 1922 AP = cmplx.Abs(complex(P2R, P2I)) 1923 P1R = 1.0e0 / AP 1924 tmp = cmplx.Exp(complex(PTR, PTI)) 1925 STR = real(tmp) 1926 STI = imag(tmp) 1927 CKR = STR * P1R 1928 CKI = STI * P1R 1929 PTR = P2R * P1R 1930 PTI = -P2I * P1R 1931 tmp = complex(CKR, CKI) * complex(PTR, PTI) 1932 CNORMR = real(tmp) 1933 CNORMI = imag(tmp) 1934 for I = 1; I <= N; I++ { 1935 STR = YR[I]*CNORMR - YI[I]*CNORMI 1936 YI[I] = YR[I]*CNORMI + YI[I]*CNORMR 1937 YR[I] = STR 1938 } 1939 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL 1940 OneTen: 1941 NZ = -2 1942 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL 1943 } 1944 1945 // Zseri computes the I bessel function for real(z) >= 0 by means of the power 1946 // series for large |z| in the region |z| <= 2*sqrt(fnu+1). 1947 // 1948 // nz = 0 is a normal return. nz > 0 means that the last nz components were set 1949 // to zero due to underflow. nz < 0 means that underflow occurred, but the 1950 // condition |z| <= 2*sqrt(fnu+1) was violated and the computation must be 1951 // completed in another routine with n -= abs(nz). 1952 func Zseri(z complex128, fnu float64, kode, n int, y []complex128, tol, elim, alim float64) (nz int) { 1953 // TODO(btracey): The original fortran line is "ARM = 1.0D+3*D1MACH(1)". Evidently, in Fortran 1954 // this is interpreted as one to the power of +3*D1MACH(1). While it is possible 1955 // this was intentional, it seems unlikely. 1956 arm := 1000 * dmach[1] 1957 az := cmplx.Abs(z) 1958 if az < arm { 1959 for i := 0; i < n; i++ { 1960 y[i] = 0 1961 } 1962 if fnu == 0 { 1963 y[0] = 1 1964 n-- 1965 } 1966 if az == 0 { 1967 return 0 1968 } 1969 return n 1970 } 1971 hz := 0.5 * z 1972 var cz complex128 1973 var acz float64 1974 if az > math.Sqrt(arm) { 1975 cz = hz * hz 1976 acz = cmplx.Abs(cz) 1977 } 1978 NN := n 1979 ck := cmplx.Log(hz) 1980 var ak1 complex128 1981 for { 1982 dfnu := fnu + float64(NN-1) 1983 // Underflow test. 1984 ak1 = ck * complex(dfnu, 0) 1985 ak := dgamln(dfnu+1, 0) 1986 ak1 -= complex(ak, 0) 1987 if kode == 2 { 1988 ak1 -= complex(real(z), 0) 1989 } 1990 if real(ak1) > -elim { 1991 break 1992 } 1993 nz++ 1994 y[NN-1] = 0 1995 if acz > dfnu { 1996 // Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation 1997 // in cbinu with n = n - abs(nz). 1998 nz *= -1 1999 return nz 2000 } 2001 NN-- 2002 if NN == 0 { 2003 return nz 2004 } 2005 } 2006 crscr := 1.0 2007 var flag int 2008 var scale float64 2009 aa := real(ak1) 2010 if aa <= -alim { 2011 flag = 1 2012 crscr = tol 2013 scale = arm / tol 2014 aa -= math.Log(tol) 2015 } 2016 var w [2]complex128 2017 for { 2018 coef := cmplx.Exp(complex(aa, imag(ak1))) 2019 atol := tol * acz / (fnu + float64(NN)) 2020 for i := 0; i < min(2, NN); i++ { 2021 FNUP := fnu + float64(NN-i) 2022 s1 := 1 + 0i 2023 if acz >= tol*FNUP { 2024 ak2 := 1 + 0i 2025 ak := FNUP + 2 2026 S := FNUP 2027 scl := 2.0 2028 first := true 2029 for first || scl > atol { 2030 ak2 = ak2 * cz * complex(1/S, 0) 2031 scl *= acz / S 2032 s1 += ak2 2033 S += ak 2034 ak += 2 2035 first = false 2036 } 2037 } 2038 s2 := s1 * coef 2039 w[i] = s2 2040 if flag == 1 { 2041 if Zuchk(s2, scale, tol) != 0 { 2042 var full bool 2043 var dfnu float64 2044 // This code is similar to the code that exists above. The 2045 // code copying is here because the original Fortran used 2046 // a goto to solve the loop-and-a-half problem. Removing the 2047 // goto makes the behavior of the function and variable scoping 2048 // much clearer, but requires copying this code due to Go's 2049 // goto rules. 2050 for { 2051 if full { 2052 dfnu = fnu + float64(NN-1) 2053 // Underflow test. 2054 ak1 = ck * complex(dfnu, 0) 2055 ak1 -= complex(dgamln(dfnu+1, 0), 0) 2056 if kode == 2 { 2057 ak1 -= complex(real(z), 0) 2058 } 2059 if real(ak1) > -elim { 2060 break 2061 } 2062 } else { 2063 full = true 2064 } 2065 nz++ 2066 y[NN-1] = 0 2067 if acz > dfnu { 2068 // Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation 2069 // in cbinu with n = n - abs(nz). 2070 nz *= -1 2071 return nz 2072 } 2073 NN-- 2074 if NN == 0 { 2075 return nz 2076 } 2077 } 2078 continue 2079 } 2080 } 2081 y[NN-i-1] = s2 * complex(crscr, 0) 2082 coef /= hz 2083 coef *= complex(FNUP-1, 0) 2084 } 2085 break 2086 } 2087 if NN <= 2 { 2088 return nz 2089 } 2090 rz := complex(2*real(z)/(az*az), -2*imag(z)/(az*az)) 2091 if flag == 0 { 2092 for i := NN - 3; i >= 0; i-- { 2093 y[i] = complex(float64(i+1)+fnu, 0)*rz*y[i+1] + y[i+2] 2094 } 2095 return nz 2096 } 2097 2098 // exp(-alim)=exp(-elim)/tol=approximately one digit of precision above the 2099 // underflow limit, which equals scale = dmach[1)*SS*1e3. 2100 s1 := w[0] 2101 s2 := w[1] 2102 for K := NN - 3; K >= 0; K-- { 2103 s1, s2 = s2, s1+complex(float64(K+1)+fnu, 0)*(rz*s2) 2104 ck := s2 * complex(crscr, 0) 2105 y[K] = ck 2106 if cmplx.Abs(ck) > scale { 2107 for ; K >= 0; K-- { 2108 y[K] = complex(float64(K+1)+fnu, 0)*rz*y[K+1] + y[K+2] 2109 } 2110 return nz 2111 } 2112 } 2113 return nz 2114 } 2115 2116 // Zs1s2 tests for a possible underflow resulting from the addition of the I and 2117 // K functions in the analytic continuation formula where s1 == K function and 2118 // s2 == I function. 2119 // 2120 // When kode == 1, the I and K functions are different orders of magnitude. 2121 // 2122 // When kode == 2, they may both be of the same order of magnitude, but the maximum 2123 // must be at least one precision above the underflow limit. 2124 func Zs1s2(zr, s1, s2 complex128, scale, lim float64, iuf int) (s1o, s2o complex128, nz, iufo int) { 2125 if s1 == 0 || math.Log(cmplx.Abs(s1))-2*real(zr) < -lim { 2126 if cmplx.Abs(s2) > scale { 2127 return 0, s2, 0, iuf 2128 } 2129 return 0, 0, 1, 0 2130 } 2131 // TODO(btracey): Written like this for numerical rounding reasons. 2132 // Fix once we're sure other changes are correct. 2133 s1 = cmplx.Exp(cmplx.Log(s1) - zr - zr) 2134 if math.Max(cmplx.Abs(s1), cmplx.Abs(s2)) > scale { 2135 return s1, s2, 0, iuf + 1 2136 } 2137 return 0, 0, 1, 0 2138 } 2139 2140 func dgamln(z float64, ierr int) float64 { 2141 //return amoslib.DgamlnFort(z) 2142 // Go implementation. 2143 if z < 0 { 2144 return 0 2145 } 2146 a2, _ := math.Lgamma(z) 2147 return a2 2148 }