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