gonum.org/v1/gonum@v0.14.0/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 // 1385 // 1e3 + 3*dmach(1)/tol 1386 // 1387 // y is accepted if the underflow is at least one precision below the magnitude 1388 // of the largest component. Otherwise an underflow is assumed as the phase angle 1389 // does not have sufficient accuracy. 1390 func Zuchk(y complex128, scale, tol float64) int { 1391 absR := math.Abs(real(y)) 1392 absI := math.Abs(imag(y)) 1393 minAbs := math.Min(absR, absI) 1394 if minAbs > scale { 1395 return 0 1396 } 1397 maxAbs := math.Max(absR, absI) 1398 minAbs /= tol 1399 if maxAbs < minAbs { 1400 return 1 1401 } 1402 return 0 1403 } 1404 1405 // ZACAI APPLIES THE ANALYTIC CONTINUATION FORMULA 1406 // 1407 // K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN) 1408 // MP=PI*MR*CMPLX(0.0,1.0) 1409 // 1410 // TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT 1411 // HALF Z PLANE FOR USE WITH ZAIRY WHERE FNU=1/3 OR 2/3 AND N=1. 1412 // ZACAI IS THE SAME AS ZACON WITH THE PARTS FOR LARGER ORDERS AND 1413 // RECURRENCE REMOVED. A RECURSIVE CALL TO ZACON CAN RESULT if ZACON 1414 // IS CALLED FROM ZAIRY. 1415 func Zacai(ZR, ZI, FNU float64, KODE, MR, N int, YR, YI []float64, RL, TOL, ELIM, ALIM float64) ( 1416 ZRout, ZIout, FNUout float64, KODEout, MRout, Nout int, YRout, YIout []float64, NZ int, RLout, TOLout, ELIMout, ALIMout float64) { 1417 var ARG, ASCLE, AZ, CSGNR, CSGNI, CSPNR, 1418 CSPNI, C1R, C1I, C2R, C2I, DFNU, FMR, PI, 1419 SGN, YY, ZNR, ZNI float64 1420 var INU, IUF, NN, NW int 1421 var zn, c1, c2, z complex128 1422 var y []complex128 1423 //var sin, cos float64 1424 1425 CYR := []float64{math.NaN(), 0, 0} 1426 CYI := []float64{math.NaN(), 0, 0} 1427 1428 PI = math.Pi 1429 ZNR = -ZR 1430 ZNI = -ZI 1431 AZ = cmplx.Abs(complex(ZR, ZI)) 1432 NN = N 1433 DFNU = FNU + float64(float32(N-1)) 1434 if AZ <= 2.0e0 { 1435 goto Ten 1436 } 1437 if AZ*AZ*0.25 > DFNU+1.0e0 { 1438 goto Twenty 1439 } 1440 Ten: 1441 // POWER SERIES FOR THE I FUNCTION. 1442 z = complex(ZNR, ZNI) 1443 y = make([]complex128, len(YR)) 1444 for i, v := range YR { 1445 y[i] = complex(v, YI[i]) 1446 } 1447 Zseri(z, FNU, KODE, NN, y[1:], TOL, ELIM, ALIM) 1448 for i, v := range y { 1449 YR[i] = real(v) 1450 YI[i] = imag(v) 1451 } 1452 goto Forty 1453 Twenty: 1454 if AZ < RL { 1455 goto Thirty 1456 } 1457 // ASYMPTOTIC EXPANSION FOR LARGE Z FOR THE I FUNCTION. 1458 ZNR, ZNI, FNU, KODE, _, YR, YI, NW, RL, TOL, ELIM, ALIM = Zasyi(ZNR, ZNI, FNU, KODE, NN, YR, YI, RL, TOL, ELIM, ALIM) 1459 if NW < 0 { 1460 goto Eighty 1461 } 1462 goto Forty 1463 Thirty: 1464 // MILLER ALGORITHM NORMALIZED BY THE SERIES FOR THE I FUNCTION 1465 ZNR, ZNI, FNU, KODE, _, YR, YI, NW, TOL = Zmlri(ZNR, ZNI, FNU, KODE, NN, YR, YI, TOL) 1466 if NW < 0 { 1467 goto Eighty 1468 } 1469 Forty: 1470 // ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION. 1471 ZNR, ZNI, FNU, KODE, _, CYR, CYI, NW, TOL, ELIM, ALIM = Zbknu(ZNR, ZNI, FNU, KODE, 1, CYR, CYI, TOL, ELIM, ALIM) 1472 if NW != 0 { 1473 goto Eighty 1474 } 1475 FMR = float64(float32(MR)) 1476 SGN = -math.Copysign(PI, FMR) 1477 CSGNR = 0.0e0 1478 CSGNI = SGN 1479 if KODE == 1 { 1480 goto Fifty 1481 } 1482 YY = -ZNI 1483 //sin, cos = math.Sincos(YY) 1484 CSGNR = -CSGNI * math.Sin(YY) 1485 CSGNI = CSGNI * math.Cos(YY) 1486 Fifty: 1487 // CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE 1488 // WHEN FNU IS LARGE 1489 INU = int(float32(FNU)) 1490 ARG = (FNU - float64(float32(INU))) * SGN 1491 //sin, cos = math.Sincos(ARG) 1492 CSPNR = math.Cos(ARG) 1493 CSPNI = math.Sin(ARG) 1494 if INU%2 == 0 { 1495 goto Sixty 1496 } 1497 CSPNR = -CSPNR 1498 CSPNI = -CSPNI 1499 Sixty: 1500 C1R = CYR[1] 1501 C1I = CYI[1] 1502 C2R = YR[1] 1503 C2I = YI[1] 1504 if KODE == 1 { 1505 goto Seventy 1506 } 1507 IUF = 0 1508 ASCLE = 1.0e+3 * dmach[1] / TOL 1509 zn = complex(ZNR, ZNI) 1510 c1 = complex(C1R, C1I) 1511 c2 = complex(C2R, C2I) 1512 c1, c2, NW, _ = Zs1s2(zn, c1, c2, ASCLE, ALIM, IUF) 1513 C1R = real(c1) 1514 C1I = imag(c1) 1515 C2R = real(c2) 1516 C2I = imag(c2) 1517 NZ = NZ + NW 1518 Seventy: 1519 YR[1] = CSPNR*C1R - CSPNI*C1I + CSGNR*C2R - CSGNI*C2I 1520 YI[1] = CSPNR*C1I + CSPNI*C1R + CSGNR*C2I + CSGNI*C2R 1521 return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1522 Eighty: 1523 NZ = -1 1524 if NW == -2 { 1525 NZ = -2 1526 } 1527 return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1528 } 1529 1530 // ZASYI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z)>=0.0 BY 1531 // MEANS OF THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z) IN THE 1532 // REGION CABS(Z)>MAX(RL,FNU*FNU/2). NZ=0 IS A NORMAL return. 1533 // NZ<0 INDICATES AN OVERFLOW ON KODE=1. 1534 func Zasyi(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, RL, TOL, ELIM, ALIM float64) ( 1535 ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, RLout, TOLout, ELIMout, ALIMout float64) { 1536 var AA, AEZ, AK, AK1I, AK1R, ARG, ARM, ATOL, 1537 AZ, BB, BK, CKI, CKR, CONEI, CONER, CS1I, CS1R, CS2I, CS2R, CZI, 1538 CZR, DFNU, DKI, DKR, DNU2, EZI, EZR, FDN, PI, P1I, 1539 P1R, RAZ, RTPI, RTR1, RZI, RZR, S, SGN, SQK, STI, STR, S2I, 1540 S2R, TZI, TZR, ZEROI, ZEROR float64 1541 1542 var I, IB, IL, INU, J, JL, K, KODED, M, NN int 1543 var tmp complex128 1544 // var sin, cos float64 1545 1546 PI = math.Pi 1547 RTPI = 0.159154943091895336e0 1548 ZEROR = 0 1549 ZEROI = 0 1550 CONER = 1 1551 CONEI = 0 1552 1553 AZ = cmplx.Abs(complex(ZR, ZI)) 1554 ARM = 1.0e3 * dmach[1] 1555 RTR1 = math.Sqrt(ARM) 1556 IL = min(2, N) 1557 DFNU = FNU + float64(float32(N-IL)) 1558 1559 // OVERFLOW TEST 1560 RAZ = 1.0e0 / AZ 1561 STR = ZR * RAZ 1562 STI = -ZI * RAZ 1563 AK1R = RTPI * STR * RAZ 1564 AK1I = RTPI * STI * RAZ 1565 tmp = cmplx.Sqrt(complex(AK1R, AK1I)) 1566 AK1R = real(tmp) 1567 AK1I = imag(tmp) 1568 CZR = ZR 1569 CZI = ZI 1570 if KODE != 2 { 1571 goto Ten 1572 } 1573 CZR = ZEROR 1574 CZI = ZI 1575 Ten: 1576 if math.Abs(CZR) > ELIM { 1577 goto OneHundred 1578 } 1579 DNU2 = DFNU + DFNU 1580 KODED = 1 1581 if (math.Abs(CZR) > ALIM) && (N > 2) { 1582 goto Twenty 1583 } 1584 KODED = 0 1585 tmp = cmplx.Exp(complex(CZR, CZI)) 1586 STR = real(tmp) 1587 STI = imag(tmp) 1588 tmp = complex(AK1R, AK1I) * complex(STR, STI) 1589 AK1R = real(tmp) 1590 AK1I = imag(tmp) 1591 Twenty: 1592 FDN = 0.0e0 1593 if DNU2 > RTR1 { 1594 FDN = DNU2 * DNU2 1595 } 1596 EZR = ZR * 8.0e0 1597 EZI = ZI * 8.0e0 1598 1599 // WHEN Z IS IMAGINARY, THE ERROR TEST MUST BE MADE RELATIVE TO THE 1600 // FIRST RECIPROCAL POWER SINCE THIS IS THE LEADING TERM OF THE 1601 // EXPANSION FOR THE IMAGINARY PART. 1602 AEZ = 8.0e0 * AZ 1603 S = TOL / AEZ 1604 JL = int(float32(RL+RL)) + 2 1605 P1R = ZEROR 1606 P1I = ZEROI 1607 if ZI == 0.0e0 { 1608 goto Thirty 1609 } 1610 1611 // CALCULATE EXP(PI*(0.5+FNU+N-IL)*I) TO MINIMIZE LOSSES OF 1612 // SIGNIFICANCE WHEN FNU OR N IS LARGE 1613 INU = int(float32(FNU)) 1614 ARG = (FNU - float64(float32(INU))) * PI 1615 INU = INU + N - IL 1616 //sin, cos = math.Sincos(ARG) 1617 AK = -math.Sin(ARG) 1618 BK = math.Cos(ARG) 1619 if ZI < 0.0e0 { 1620 BK = -BK 1621 } 1622 P1R = AK 1623 P1I = BK 1624 if INU%2 == 0 { 1625 goto Thirty 1626 } 1627 P1R = -P1R 1628 P1I = -P1I 1629 Thirty: 1630 for K = 1; K <= IL; K++ { 1631 SQK = FDN - 1.0e0 1632 ATOL = S * math.Abs(SQK) 1633 SGN = 1.0e0 1634 CS1R = CONER 1635 CS1I = CONEI 1636 CS2R = CONER 1637 CS2I = CONEI 1638 CKR = CONER 1639 CKI = CONEI 1640 AK = 0.0e0 1641 AA = 1.0e0 1642 BB = AEZ 1643 DKR = EZR 1644 DKI = EZI 1645 // TODO(btracey): This loop is executed tens of thousands of times. Why? 1646 // is that really necessary? 1647 for J = 1; J <= JL; J++ { 1648 tmp = complex(CKR, CKI) / complex(DKR, DKI) 1649 STR = real(tmp) 1650 STI = imag(tmp) 1651 CKR = STR * SQK 1652 CKI = STI * SQK 1653 CS2R = CS2R + CKR 1654 CS2I = CS2I + CKI 1655 SGN = -SGN 1656 CS1R = CS1R + CKR*SGN 1657 CS1I = CS1I + CKI*SGN 1658 DKR = DKR + EZR 1659 DKI = DKI + EZI 1660 AA = AA * math.Abs(SQK) / BB 1661 BB = BB + AEZ 1662 AK = AK + 8.0e0 1663 SQK = SQK - AK 1664 if AA <= ATOL { 1665 goto Fifty 1666 } 1667 } 1668 goto OneTen 1669 Fifty: 1670 S2R = CS1R 1671 S2I = CS1I 1672 if ZR+ZR >= ELIM { 1673 goto Sixty 1674 } 1675 TZR = ZR + ZR 1676 TZI = ZI + ZI 1677 tmp = cmplx.Exp(complex(-TZR, -TZI)) 1678 STR = real(tmp) 1679 STI = imag(tmp) 1680 tmp = complex(STR, STI) * complex(P1R, P1I) 1681 STR = real(tmp) 1682 STI = imag(tmp) 1683 tmp = complex(STR, STI) * complex(CS2R, CS2I) 1684 STR = real(tmp) 1685 STI = imag(tmp) 1686 S2R = S2R + STR 1687 S2I = S2I + STI 1688 Sixty: 1689 FDN = FDN + 8.0e0*DFNU + 4.0e0 1690 P1R = -P1R 1691 P1I = -P1I 1692 M = N - IL + K 1693 YR[M] = S2R*AK1R - S2I*AK1I 1694 YI[M] = S2R*AK1I + S2I*AK1R 1695 } 1696 if N <= 2 { 1697 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1698 } 1699 NN = N 1700 K = NN - 2 1701 AK = float64(float32(K)) 1702 STR = ZR * RAZ 1703 STI = -ZI * RAZ 1704 RZR = (STR + STR) * RAZ 1705 RZI = (STI + STI) * RAZ 1706 IB = 3 1707 for I = IB; I <= NN; I++ { 1708 YR[K] = (AK+FNU)*(RZR*YR[K+1]-RZI*YI[K+1]) + YR[K+2] 1709 YI[K] = (AK+FNU)*(RZR*YI[K+1]+RZI*YR[K+1]) + YI[K+2] 1710 AK = AK - 1.0e0 1711 K = K - 1 1712 } 1713 if KODED == 0 { 1714 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1715 } 1716 tmp = cmplx.Exp(complex(CZR, CZI)) 1717 CKR = real(tmp) 1718 CKI = imag(tmp) 1719 for I = 1; I <= NN; I++ { 1720 STR = YR[I]*CKR - YI[I]*CKI 1721 YI[I] = YR[I]*CKI + YI[I]*CKR 1722 YR[I] = STR 1723 } 1724 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1725 OneHundred: 1726 NZ = -1 1727 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1728 OneTen: 1729 NZ = -2 1730 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM 1731 } 1732 1733 // ZMLRI COMPUTES THE I BESSEL FUNCTION FOR RE(Z)>=0.0 BY THE 1734 // MILLER ALGORITHM NORMALIZED BY A NEUMANN SERIES. 1735 func Zmlri(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, TOL float64) ( 1736 ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZ int, TOLout float64) { 1737 var ACK, AK, AP, AT, AZ, BK, CKI, CKR, CNORMI, 1738 CNORMR, CONEI, CONER, FKAP, FKK, FLAM, FNF, PTI, PTR, P1I, 1739 P1R, P2I, P2R, RAZ, RHO, RHO2, RZI, RZR, SCLE, STI, STR, SUMI, 1740 SUMR, TFNF, TST, ZEROI, ZEROR float64 1741 var I, IAZ, IDUM, IFNU, INU, ITIME, K, KK, KM, M int 1742 var tmp complex128 1743 ZEROR = 0 1744 ZEROI = 0 1745 CONER = 1 1746 CONEI = 0 1747 1748 SCLE = dmach[1] / TOL 1749 AZ = cmplx.Abs(complex(ZR, ZI)) 1750 IAZ = int(float32(AZ)) 1751 IFNU = int(float32(FNU)) 1752 INU = IFNU + N - 1 1753 AT = float64(float32(IAZ)) + 1.0e0 1754 RAZ = 1.0e0 / AZ 1755 STR = ZR * RAZ 1756 STI = -ZI * RAZ 1757 CKR = STR * AT * RAZ 1758 CKI = STI * AT * RAZ 1759 RZR = (STR + STR) * RAZ 1760 RZI = (STI + STI) * RAZ 1761 P1R = ZEROR 1762 P1I = ZEROI 1763 P2R = CONER 1764 P2I = CONEI 1765 ACK = (AT + 1.0e0) * RAZ 1766 RHO = ACK + math.Sqrt(ACK*ACK-1.0e0) 1767 RHO2 = RHO * RHO 1768 TST = (RHO2 + RHO2) / ((RHO2 - 1.0e0) * (RHO - 1.0e0)) 1769 TST = TST / TOL 1770 1771 // COMPUTE RELATIVE TRUNCATION ERROR INDEX FOR SERIES. 1772 //fmt.Println("before loop", P2R, P2I, CKR, CKI, RZR, RZI, TST, AK) 1773 AK = AT 1774 for I = 1; I <= 80; I++ { 1775 PTR = P2R 1776 PTI = P2I 1777 P2R = P1R - (CKR*PTR - CKI*PTI) 1778 P2I = P1I - (CKI*PTR + CKR*PTI) 1779 P1R = PTR 1780 P1I = PTI 1781 CKR = CKR + RZR 1782 CKI = CKI + RZI 1783 AP = cmplx.Abs(complex(P2R, P2I)) 1784 if AP > TST*AK*AK { 1785 goto Twenty 1786 } 1787 AK = AK + 1.0e0 1788 } 1789 goto OneTen 1790 Twenty: 1791 I = I + 1 1792 K = 0 1793 if INU < IAZ { 1794 goto Forty 1795 } 1796 // COMPUTE RELATIVE TRUNCATION ERROR FOR RATIOS. 1797 P1R = ZEROR 1798 P1I = ZEROI 1799 P2R = CONER 1800 P2I = CONEI 1801 AT = float64(float32(INU)) + 1.0e0 1802 STR = ZR * RAZ 1803 STI = -ZI * RAZ 1804 CKR = STR * AT * RAZ 1805 CKI = STI * AT * RAZ 1806 ACK = AT * RAZ 1807 TST = math.Sqrt(ACK / TOL) 1808 ITIME = 1 1809 for K = 1; K <= 80; K++ { 1810 PTR = P2R 1811 PTI = P2I 1812 P2R = P1R - (CKR*PTR - CKI*PTI) 1813 P2I = P1I - (CKR*PTI + CKI*PTR) 1814 P1R = PTR 1815 P1I = PTI 1816 CKR = CKR + RZR 1817 CKI = CKI + RZI 1818 AP = cmplx.Abs(complex(P2R, P2I)) 1819 if AP < TST { 1820 continue 1821 } 1822 if ITIME == 2 { 1823 goto Forty 1824 } 1825 ACK = cmplx.Abs(complex(CKR, CKI)) 1826 FLAM = ACK + math.Sqrt(ACK*ACK-1.0e0) 1827 FKAP = AP / cmplx.Abs(complex(P1R, P1I)) 1828 RHO = math.Min(FLAM, FKAP) 1829 TST = TST * math.Sqrt(RHO/(RHO*RHO-1.0e0)) 1830 ITIME = 2 1831 } 1832 goto OneTen 1833 Forty: 1834 // BACKWARD RECURRENCE AND SUM NORMALIZING RELATION. 1835 K = K + 1 1836 KK = max(I+IAZ, K+INU) 1837 FKK = float64(float32(KK)) 1838 P1R = ZEROR 1839 P1I = ZEROI 1840 1841 // SCALE P2 AND SUM BY SCLE. 1842 P2R = SCLE 1843 P2I = ZEROI 1844 FNF = FNU - float64(float32(IFNU)) 1845 TFNF = FNF + FNF 1846 BK = dgamln(FKK+TFNF+1.0e0, IDUM) - dgamln(FKK+1.0e0, IDUM) - dgamln(TFNF+1.0e0, IDUM) 1847 BK = math.Exp(BK) 1848 SUMR = ZEROR 1849 SUMI = ZEROI 1850 KM = KK - INU 1851 for I = 1; I <= KM; I++ { 1852 PTR = P2R 1853 PTI = P2I 1854 P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) 1855 P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) 1856 P1R = PTR 1857 P1I = PTI 1858 AK = 1.0e0 - TFNF/(FKK+TFNF) 1859 ACK = BK * AK 1860 SUMR = SUMR + (ACK+BK)*P1R 1861 SUMI = SUMI + (ACK+BK)*P1I 1862 BK = ACK 1863 FKK = FKK - 1.0e0 1864 } 1865 YR[N] = P2R 1866 YI[N] = P2I 1867 if N == 1 { 1868 goto Seventy 1869 } 1870 for I = 2; I <= N; I++ { 1871 PTR = P2R 1872 PTI = P2I 1873 P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) 1874 P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI) 1875 P1R = PTR 1876 P1I = PTI 1877 AK = 1.0e0 - TFNF/(FKK+TFNF) 1878 ACK = BK * AK 1879 SUMR = SUMR + (ACK+BK)*P1R 1880 SUMI = SUMI + (ACK+BK)*P1I 1881 BK = ACK 1882 FKK = FKK - 1.0e0 1883 M = N - I + 1 1884 YR[M] = P2R 1885 YI[M] = P2I 1886 } 1887 Seventy: 1888 if IFNU <= 0 { 1889 goto Ninety 1890 } 1891 for I = 1; I <= IFNU; I++ { 1892 PTR = P2R 1893 PTI = P2I 1894 P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI) 1895 P2I = P1I + (FKK+FNF)*(RZR*PTI+RZI*PTR) 1896 P1R = PTR 1897 P1I = PTI 1898 AK = 1.0e0 - TFNF/(FKK+TFNF) 1899 ACK = BK * AK 1900 SUMR = SUMR + (ACK+BK)*P1R 1901 SUMI = SUMI + (ACK+BK)*P1I 1902 BK = ACK 1903 FKK = FKK - 1.0e0 1904 } 1905 Ninety: 1906 PTR = ZR 1907 PTI = ZI 1908 if KODE == 2 { 1909 PTR = ZEROR 1910 } 1911 tmp = cmplx.Log(complex(RZR, RZI)) 1912 STR = real(tmp) 1913 STI = imag(tmp) 1914 P1R = -FNF*STR + PTR 1915 P1I = -FNF*STI + PTI 1916 AP = dgamln(1.0e0+FNF, IDUM) 1917 PTR = P1R - AP 1918 PTI = P1I 1919 1920 // THE DIVISION CEXP(PT)/(SUM+P2) IS ALTERED TO AVOID OVERFLOW 1921 // IN THE DENOMINATOR BY SQUARING LARGE QUANTITIES. 1922 P2R = P2R + SUMR 1923 P2I = P2I + SUMI 1924 AP = cmplx.Abs(complex(P2R, P2I)) 1925 P1R = 1.0e0 / AP 1926 tmp = cmplx.Exp(complex(PTR, PTI)) 1927 STR = real(tmp) 1928 STI = imag(tmp) 1929 CKR = STR * P1R 1930 CKI = STI * P1R 1931 PTR = P2R * P1R 1932 PTI = -P2I * P1R 1933 tmp = complex(CKR, CKI) * complex(PTR, PTI) 1934 CNORMR = real(tmp) 1935 CNORMI = imag(tmp) 1936 for I = 1; I <= N; I++ { 1937 STR = YR[I]*CNORMR - YI[I]*CNORMI 1938 YI[I] = YR[I]*CNORMI + YI[I]*CNORMR 1939 YR[I] = STR 1940 } 1941 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL 1942 OneTen: 1943 NZ = -2 1944 return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL 1945 } 1946 1947 // Zseri computes the I bessel function for real(z) >= 0 by means of the power 1948 // series for large |z| in the region |z| <= 2*sqrt(fnu+1). 1949 // 1950 // nz = 0 is a normal return. nz > 0 means that the last nz components were set 1951 // to zero due to underflow. nz < 0 means that underflow occurred, but the 1952 // condition |z| <= 2*sqrt(fnu+1) was violated and the computation must be 1953 // completed in another routine with n -= abs(nz). 1954 func Zseri(z complex128, fnu float64, kode, n int, y []complex128, tol, elim, alim float64) (nz int) { 1955 // TODO(btracey): The original fortran line is "ARM = 1.0D+3*D1MACH(1)". Evidently, in Fortran 1956 // this is interpreted as one to the power of +3*D1MACH(1). While it is possible 1957 // this was intentional, it seems unlikely. 1958 arm := 1000 * dmach[1] 1959 az := cmplx.Abs(z) 1960 if az < arm { 1961 for i := 0; i < n; i++ { 1962 y[i] = 0 1963 } 1964 if fnu == 0 { 1965 y[0] = 1 1966 n-- 1967 } 1968 if az == 0 { 1969 return 0 1970 } 1971 return n 1972 } 1973 hz := 0.5 * z 1974 var cz complex128 1975 var acz float64 1976 if az > math.Sqrt(arm) { 1977 cz = hz * hz 1978 acz = cmplx.Abs(cz) 1979 } 1980 NN := n 1981 ck := cmplx.Log(hz) 1982 var ak1 complex128 1983 for { 1984 dfnu := fnu + float64(NN-1) 1985 // Underflow test. 1986 ak1 = ck * complex(dfnu, 0) 1987 ak := dgamln(dfnu+1, 0) 1988 ak1 -= complex(ak, 0) 1989 if kode == 2 { 1990 ak1 -= complex(real(z), 0) 1991 } 1992 if real(ak1) > -elim { 1993 break 1994 } 1995 nz++ 1996 y[NN-1] = 0 1997 if acz > dfnu { 1998 // Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation 1999 // in cbinu with n = n - abs(nz). 2000 nz *= -1 2001 return nz 2002 } 2003 NN-- 2004 if NN == 0 { 2005 return nz 2006 } 2007 } 2008 crscr := 1.0 2009 var flag int 2010 var scale float64 2011 aa := real(ak1) 2012 if aa <= -alim { 2013 flag = 1 2014 crscr = tol 2015 scale = arm / tol 2016 aa -= math.Log(tol) 2017 } 2018 var w [2]complex128 2019 for { 2020 coef := cmplx.Exp(complex(aa, imag(ak1))) 2021 atol := tol * acz / (fnu + float64(NN)) 2022 for i := 0; i < min(2, NN); i++ { 2023 FNUP := fnu + float64(NN-i) 2024 s1 := 1 + 0i 2025 if acz >= tol*FNUP { 2026 ak2 := 1 + 0i 2027 ak := FNUP + 2 2028 S := FNUP 2029 scl := 2.0 2030 first := true 2031 for first || scl > atol { 2032 ak2 = ak2 * cz * complex(1/S, 0) 2033 scl *= acz / S 2034 s1 += ak2 2035 S += ak 2036 ak += 2 2037 first = false 2038 } 2039 } 2040 s2 := s1 * coef 2041 w[i] = s2 2042 if flag == 1 { 2043 if Zuchk(s2, scale, tol) != 0 { 2044 var full bool 2045 var dfnu float64 2046 // This code is similar to the code that exists above. The 2047 // code copying is here because the original Fortran used 2048 // a goto to solve the loop-and-a-half problem. Removing the 2049 // goto makes the behavior of the function and variable scoping 2050 // much clearer, but requires copying this code due to Go's 2051 // goto rules. 2052 for { 2053 if full { 2054 dfnu = fnu + float64(NN-1) 2055 // Underflow test. 2056 ak1 = ck * complex(dfnu, 0) 2057 ak1 -= complex(dgamln(dfnu+1, 0), 0) 2058 if kode == 2 { 2059 ak1 -= complex(real(z), 0) 2060 } 2061 if real(ak1) > -elim { 2062 break 2063 } 2064 } else { 2065 full = true 2066 } 2067 nz++ 2068 y[NN-1] = 0 2069 if acz > dfnu { 2070 // Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation 2071 // in cbinu with n = n - abs(nz). 2072 nz *= -1 2073 return nz 2074 } 2075 NN-- 2076 if NN == 0 { 2077 return nz 2078 } 2079 } 2080 continue 2081 } 2082 } 2083 y[NN-i-1] = s2 * complex(crscr, 0) 2084 coef /= hz 2085 coef *= complex(FNUP-1, 0) 2086 } 2087 break 2088 } 2089 if NN <= 2 { 2090 return nz 2091 } 2092 rz := complex(2*real(z)/(az*az), -2*imag(z)/(az*az)) 2093 if flag == 0 { 2094 for i := NN - 3; i >= 0; i-- { 2095 y[i] = complex(float64(i+1)+fnu, 0)*rz*y[i+1] + y[i+2] 2096 } 2097 return nz 2098 } 2099 2100 // exp(-alim)=exp(-elim)/tol=approximately one digit of precision above the 2101 // underflow limit, which equals scale = dmach[1)*SS*1e3. 2102 s1 := w[0] 2103 s2 := w[1] 2104 for K := NN - 3; K >= 0; K-- { 2105 s1, s2 = s2, s1+complex(float64(K+1)+fnu, 0)*(rz*s2) 2106 ck := s2 * complex(crscr, 0) 2107 y[K] = ck 2108 if cmplx.Abs(ck) > scale { 2109 for ; K >= 0; K-- { 2110 y[K] = complex(float64(K+1)+fnu, 0)*rz*y[K+1] + y[K+2] 2111 } 2112 return nz 2113 } 2114 } 2115 return nz 2116 } 2117 2118 // Zs1s2 tests for a possible underflow resulting from the addition of the I and 2119 // K functions in the analytic continuation formula where s1 == K function and 2120 // s2 == I function. 2121 // 2122 // When kode == 1, the I and K functions are different orders of magnitude. 2123 // 2124 // When kode == 2, they may both be of the same order of magnitude, but the maximum 2125 // must be at least one precision above the underflow limit. 2126 func Zs1s2(zr, s1, s2 complex128, scale, lim float64, iuf int) (s1o, s2o complex128, nz, iufo int) { 2127 if s1 == 0 || math.Log(cmplx.Abs(s1))-2*real(zr) < -lim { 2128 if cmplx.Abs(s2) > scale { 2129 return 0, s2, 0, iuf 2130 } 2131 return 0, 0, 1, 0 2132 } 2133 // TODO(btracey): Written like this for numerical rounding reasons. 2134 // Fix once we're sure other changes are correct. 2135 s1 = cmplx.Exp(cmplx.Log(s1) - zr - zr) 2136 if math.Max(cmplx.Abs(s1), cmplx.Abs(s2)) > scale { 2137 return s1, s2, 0, iuf + 1 2138 } 2139 return 0, 0, 1, 0 2140 } 2141 2142 func dgamln(z float64, ierr int) float64 { 2143 //return amoslib.DgamlnFort(z) 2144 // Go implementation. 2145 if z < 0 { 2146 return 0 2147 } 2148 a2, _ := math.Lgamma(z) 2149 return a2 2150 }