mirror of
https://github.com/gonum/gonum.git
synced 2025-10-10 17:40:30 +08:00
2155 lines
49 KiB
Go
2155 lines
49 KiB
Go
// Copyright ©2016 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package amos
|
|
|
|
import (
|
|
"math"
|
|
"math/cmplx"
|
|
)
|
|
|
|
/*
|
|
The AMOS functions are included in SLATEC, and the SLATEC guide (http://www.netlib.org/slatec/guide) explicitly states:
|
|
"The Library is in the public domain and distributed by the Energy
|
|
Science and Technology Software Center."
|
|
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
|
|
*/
|
|
|
|
// math.NaN() are for padding to keep indexing easy.
|
|
var imach = []int{-0, 5, 6, 0, 0, 32, 4, 2, 31, 2147483647, 2, 24, -125, 127, 53, -1021, 1023}
|
|
|
|
var dmach = []float64{math.NaN(), 2.23E-308, 1.79E-308, 1.11E-16, 2.22E-16, 0.30103000998497009}
|
|
|
|
func abs(a int) int {
|
|
if a >= 0 {
|
|
return a
|
|
}
|
|
return -a
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
func max(a, b int) int {
|
|
if a > b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
func Zairy(ZR, ZI float64, ID, KODE int) (AIR, AII float64, NZ int) {
|
|
// zairy is adapted from the original Netlib code by Donald Amos.
|
|
// http://www.netlib.no/netlib/amos/zairy.f
|
|
|
|
// Original comment:
|
|
/*
|
|
C***BEGIN PROLOGUE ZAIRY
|
|
C***DATE WRITTEN 830501 (YYMMDD)
|
|
C***REVISION DATE 890801 (YYMMDD)
|
|
C***CATEGORY NO. B5K
|
|
C***KEYWORDS AIRY FUNCTION,BESSEL FUNCTIONS OF ORDER ONE THIRD
|
|
C***AUTHOR AMOS, DONALD E., SANDIA NATIONAL LABORATORIES
|
|
C***PURPOSE TO COMPUTE AIRY FUNCTIONS AI(Z) AND DAI(Z) FOR COMPLEX Z
|
|
C***DESCRIPTION
|
|
C
|
|
C ***A DOUBLE PRECISION ROUTINE***
|
|
C ON KODE=1, ZAIRY COMPUTES THE COMPLEX AIRY FUNCTION AI(Z) OR
|
|
C ITS DERIVATIVE DAI(Z)/DZ ON ID=0 OR ID=1 RESPECTIVELY. ON
|
|
C KODE=2, A SCALING OPTION CEXP(ZTA)*AI(Z) OR CEXP(ZTA)*
|
|
C DAI(Z)/DZ IS PROVIDED TO REMOVE THE EXPONENTIAL DECAY IN
|
|
C -PI/3<ARG(Z)<PI/3 AND THE EXPONENTIAL GROWTH IN
|
|
C PI/3<ABS(ARG(Z))<PI WHERE ZTA=(2/3)*Z*CSQRT(Z).
|
|
C
|
|
C WHILE THE AIRY FUNCTIONS AI(Z) AND DAI(Z)/DZ ARE ANALYTIC IN
|
|
C THE WHOLE Z PLANE, THE CORRESPONDING SCALED FUNCTIONS DEFINED
|
|
C FOR KODE=2 HAVE A CUT ALONG THE NEGATIVE REAL AXIS.
|
|
C DEFINTIONS AND NOTATION ARE FOUND IN THE NBS HANDBOOK OF
|
|
C MATHEMATICAL FUNCTIONS (REF. 1).
|
|
C
|
|
C INPUT ZR,ZI ARE DOUBLE PRECISION
|
|
C ZR,ZI - Z=CMPLX(ZR,ZI)
|
|
C ID - ORDER OF DERIVATIVE, ID=0 OR ID=1
|
|
C KODE - A PARAMETER TO INDICATE THE SCALING OPTION
|
|
C KODE= 1 returnS
|
|
C AI=AI(Z) ON ID=0 OR
|
|
C AI=DAI(Z)/DZ ON ID=1
|
|
C = 2 returnS
|
|
C AI=CEXP(ZTA)*AI(Z) ON ID=0 OR
|
|
C AI=CEXP(ZTA)*DAI(Z)/DZ ON ID=1 WHERE
|
|
C ZTA=(2/3)*Z*CSQRT(Z)
|
|
C
|
|
C OUTPUT AIR,AII ARE DOUBLE PRECISION
|
|
C AIR,AII- COMPLEX ANSWER DEPENDING ON THE CHOICES FOR ID AND
|
|
C KODE
|
|
C NZ - UNDERFLOW INDICATOR
|
|
C NZ= 0 , NORMAL return
|
|
C NZ= 1 , AI=CMPLX(0.0E0,0.0E0) DUE TO UNDERFLOW IN
|
|
C -PI/3<ARG(Z)<PI/3 ON KODE=1
|
|
C IERR - ERROR FLAG
|
|
C IERR=0, NORMAL return - COMPUTATION COMPLETED
|
|
C IERR=1, INPUT ERROR - NO COMPUTATION
|
|
C IERR=2, OVERFLOW - NO COMPUTATION, REAL(ZTA)
|
|
C TOO LARGE ON KODE=1
|
|
C IERR=3, CABS(Z) LARGE - COMPUTATION COMPLETED
|
|
C LOSSES OF SIGNIFCANCE BY ARGUMENT REDUCTION
|
|
C PRODUCE LESS THAN HALF OF MACHINE ACCURACY
|
|
C IERR=4, CABS(Z) TOO LARGE - NO COMPUTATION
|
|
C COMPLETE LOSS OF ACCURACY BY ARGUMENT
|
|
C REDUCTION
|
|
C IERR=5, ERROR - NO COMPUTATION,
|
|
C ALGORITHM TERMINATION CONDITION NOT MET
|
|
C
|
|
C***LONG DESCRIPTION
|
|
C
|
|
C AI AND DAI ARE COMPUTED FOR CABS(Z)>1.0 FROM THE K BESSEL
|
|
C FUNCTIONS BY
|
|
C
|
|
C AI(Z)=C*SQRT(Z)*K(1/3,ZTA) , DAI(Z)=-C*Z*K(2/3,ZTA)
|
|
C C=1.0/(PI*SQRT(3.0))
|
|
C ZTA=(2/3)*Z**(3/2)
|
|
C
|
|
C WITH THE POWER SERIES FOR CABS(Z)<=1.0.
|
|
C
|
|
C IN MOST COMPLEX VARIABLE COMPUTATION, ONE MUST EVALUATE ELE-
|
|
C MENTARY FUNCTIONS. WHEN THE MAGNITUDE OF Z IS LARGE, LOSSES
|
|
C OF SIGNIFICANCE BY ARGUMENT REDUCTION OCCUR. CONSEQUENTLY, IF
|
|
C THE MAGNITUDE OF ZETA=(2/3)*Z**1.5 EXCEEDS U1=SQRT(0.5/UR),
|
|
C THEN LOSSES EXCEEDING HALF PRECISION ARE LIKELY AND AN ERROR
|
|
C FLAG IERR=3 IS TRIGGERED WHERE UR=math.Max(dmach[4),1.0D-18) IS
|
|
C DOUBLE PRECISION UNIT ROUNDOFF LIMITED TO 18 DIGITS PRECISION.
|
|
C ALSO, if THE MAGNITUDE OF ZETA IS LARGER THAN U2=0.5/UR, THEN
|
|
C ALL SIGNIFICANCE IS LOST AND IERR=4. IN ORDER TO USE THE INT
|
|
C FUNCTION, ZETA MUST BE FURTHER RESTRICTED NOT TO EXCEED THE
|
|
C LARGEST INTEGER, U3=I1MACH(9). THUS, THE MAGNITUDE OF ZETA
|
|
C MUST BE RESTRICTED BY MIN(U2,U3). ON 32 BIT MACHINES, U1,U2,
|
|
C AND U3 ARE APPROXIMATELY 2.0E+3, 4.2E+6, 2.1E+9 IN SINGLE
|
|
C PRECISION ARITHMETIC AND 1.3E+8, 1.8E+16, 2.1E+9 IN DOUBLE
|
|
C PRECISION ARITHMETIC RESPECTIVELY. THIS MAKES U2 AND U3 LIMIT-
|
|
C ING IN THEIR RESPECTIVE ARITHMETICS. THIS MEANS THAT THE MAG-
|
|
C NITUDE OF Z CANNOT EXCEED 3.1E+4 IN SINGLE AND 2.1E+6 IN
|
|
C DOUBLE PRECISION ARITHMETIC. THIS ALSO MEANS THAT ONE CAN
|
|
C EXPECT TO RETAIN, IN THE WORST CASES ON 32 BIT MACHINES,
|
|
C NO DIGITS IN SINGLE PRECISION AND ONLY 7 DIGITS IN DOUBLE
|
|
C PRECISION ARITHMETIC. SIMILAR CONSIDERATIONS HOLD FOR OTHER
|
|
C MACHINES.
|
|
C
|
|
C THE APPROXIMATE RELATIVE ERROR IN THE MAGNITUDE OF A COMPLEX
|
|
C BESSEL FUNCTION CAN BE EXPRESSED BY P*10**S WHERE P=MAX(UNIT
|
|
C ROUNDOFF,1.0E-18) IS THE NOMINAL PRECISION AND 10**S REPRE-
|
|
C SENTS THE INCREASE IN ERROR DUE TO ARGUMENT REDUCTION IN THE
|
|
C ELEMENTARY FUNCTIONS. HERE, S=MAX(1,ABS(LOG10(CABS(Z))),
|
|
C ABS(LOG10(FNU))) APPROXIMATELY (I.E. S=MAX(1,ABS(EXPONENT OF
|
|
C CABS(Z),ABS(EXPONENT OF FNU)) ). HOWEVER, THE PHASE ANGLE MAY
|
|
C HAVE ONLY ABSOLUTE ACCURACY. THIS IS MOST LIKELY TO OCCUR WHEN
|
|
C ONE COMPONENT (IN ABSOLUTE VALUE) IS LARGER THAN THE OTHER BY
|
|
C SEVERAL ORDERS OF MAGNITUDE. if ONE COMPONENT IS 10**K LARGER
|
|
C THAN THE OTHER, THEN ONE CAN EXPECT ONLY MAX(ABS(LOG10(P))-K,
|
|
C 0) SIGNIFICANT DIGITS; OR, STATED ANOTHER WAY, WHEN K EXCEEDS
|
|
C THE EXPONENT OF P, NO SIGNIFICANT DIGITS REMAIN IN THE SMALLER
|
|
C COMPONENT. HOWEVER, THE PHASE ANGLE RETAINS ABSOLUTE ACCURACY
|
|
C BECAUSE, IN COMPLEX ARITHMETIC WITH PRECISION P, THE SMALLER
|
|
C COMPONENT WILL NOT (AS A RULE) DECREASE BELOW P TIMES THE
|
|
C MAGNITUDE OF THE LARGER COMPONENT. IN THESE EXTREME CASES,
|
|
C THE PRINCIPAL PHASE ANGLE IS ON THE ORDER OF +P, -P, PI/2-P,
|
|
C OR -PI/2+P.
|
|
C
|
|
C***REFERENCES HANDBOOK OF MATHEMATICAL FUNCTIONS BY M. ABRAMOWITZ
|
|
C AND I. A. STEGUN, NBS AMS SERIES 55, U.S. DEPT. OF
|
|
C COMMERCE, 1955.
|
|
C
|
|
C COMPUTATION OF BESSEL FUNCTIONS OF COMPLEX ARGUMENT
|
|
C AND LARGE ORDER BY D. E. AMOS, SAND83-0643, MAY, 1983
|
|
C
|
|
C A SUBROUTINE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX
|
|
C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, SAND85-
|
|
C 1018, MAY, 1985
|
|
C
|
|
C A PORTABLE PACKAGE FOR BESSEL FUNCTIONS OF A COMPLEX
|
|
C ARGUMENT AND NONNEGATIVE ORDER BY D. E. AMOS, TRANS.
|
|
C MATH. SOFTWARE, 1986
|
|
*/
|
|
var AI, CONE, CSQ, CY, S1, S2, TRM1, TRM2, Z, ZTA, Z3 complex128
|
|
var AA, AD, AK, ALIM, ATRM, AZ, AZ3, BK,
|
|
CC, CK, COEF, CONEI, CONER, CSQI, CSQR, C1, C2, DIG,
|
|
DK, D1, D2, ELIM, FID, FNU, PTR, RL, R1M5, SFAC, STI, STR,
|
|
S1I, S1R, S2I, S2R, TOL, TRM1I, TRM1R, TRM2I, TRM2R, TTH, ZEROI,
|
|
ZEROR, ZTAI, ZTAR, Z3I, Z3R, ALAZ, BB float64
|
|
var IERR, IFLAG, K, K1, K2, MR, NN int
|
|
var tmp complex128
|
|
|
|
// Extra element for padding.
|
|
CYR := []float64{math.NaN(), 0}
|
|
CYI := []float64{math.NaN(), 0}
|
|
|
|
_ = AI
|
|
_ = CONE
|
|
_ = CSQ
|
|
_ = CY
|
|
_ = S1
|
|
_ = S2
|
|
_ = TRM1
|
|
_ = TRM2
|
|
_ = Z
|
|
_ = ZTA
|
|
_ = Z3
|
|
|
|
TTH = 6.66666666666666667E-01
|
|
C1 = 3.55028053887817240E-01
|
|
C2 = 2.58819403792806799E-01
|
|
COEF = 1.83776298473930683E-01
|
|
ZEROR = 0
|
|
ZEROI = 0
|
|
CONER = 1
|
|
CONEI = 0
|
|
|
|
NZ = 0
|
|
if ID < 0 || ID > 1 {
|
|
IERR = 1
|
|
}
|
|
if KODE < 1 || KODE > 2 {
|
|
IERR = 1
|
|
}
|
|
if IERR != 0 {
|
|
return
|
|
}
|
|
AZ = cmplx.Abs(complex(ZR, ZI))
|
|
TOL = math.Max(dmach[4], 1.0E-18)
|
|
FID = float64(ID)
|
|
if AZ > 1.0E0 {
|
|
goto Seventy
|
|
}
|
|
|
|
// POWER SERIES FOR CABS(Z)<=1.
|
|
S1R = CONER
|
|
S1I = CONEI
|
|
S2R = CONER
|
|
S2I = CONEI
|
|
if AZ < TOL {
|
|
goto OneSeventy
|
|
}
|
|
AA = AZ * AZ
|
|
if AA < TOL/AZ {
|
|
goto Forty
|
|
}
|
|
TRM1R = CONER
|
|
TRM1I = CONEI
|
|
TRM2R = CONER
|
|
TRM2I = CONEI
|
|
ATRM = 1.0E0
|
|
STR = ZR*ZR - ZI*ZI
|
|
STI = ZR*ZI + ZI*ZR
|
|
Z3R = STR*ZR - STI*ZI
|
|
Z3I = STR*ZI + STI*ZR
|
|
AZ3 = AZ * AA
|
|
AK = 2.0E0 + FID
|
|
BK = 3.0E0 - FID - FID
|
|
CK = 4.0E0 - FID
|
|
DK = 3.0E0 + FID + FID
|
|
D1 = AK * DK
|
|
D2 = BK * CK
|
|
AD = math.Min(D1, D2)
|
|
AK = 24.0E0 + 9.0E0*FID
|
|
BK = 30.0E0 - 9.0E0*FID
|
|
for K = 1; K <= 25; K++ {
|
|
STR = (TRM1R*Z3R - TRM1I*Z3I) / D1
|
|
TRM1I = (TRM1R*Z3I + TRM1I*Z3R) / D1
|
|
TRM1R = STR
|
|
S1R = S1R + TRM1R
|
|
S1I = S1I + TRM1I
|
|
STR = (TRM2R*Z3R - TRM2I*Z3I) / D2
|
|
TRM2I = (TRM2R*Z3I + TRM2I*Z3R) / D2
|
|
TRM2R = STR
|
|
S2R = S2R + TRM2R
|
|
S2I = S2I + TRM2I
|
|
ATRM = ATRM * AZ3 / AD
|
|
D1 = D1 + AK
|
|
D2 = D2 + BK
|
|
AD = math.Min(D1, D2)
|
|
if ATRM < TOL*AD {
|
|
goto Forty
|
|
}
|
|
AK = AK + 18.0E0
|
|
BK = BK + 18.0E0
|
|
}
|
|
Forty:
|
|
if ID == 1 {
|
|
goto Fifty
|
|
}
|
|
AIR = S1R*C1 - C2*(ZR*S2R-ZI*S2I)
|
|
AII = S1I*C1 - C2*(ZR*S2I+ZI*S2R)
|
|
if KODE == 1 {
|
|
return
|
|
}
|
|
tmp = cmplx.Sqrt(complex(ZR, ZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
ZTAR = TTH * (ZR*STR - ZI*STI)
|
|
ZTAI = TTH * (ZR*STI + ZI*STR)
|
|
tmp = cmplx.Exp(complex(ZTAR, ZTAI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
PTR = AIR*STR - AII*STI
|
|
AII = AIR*STI + AII*STR
|
|
AIR = PTR
|
|
return
|
|
|
|
Fifty:
|
|
AIR = -S2R * C2
|
|
AII = -S2I * C2
|
|
if AZ <= TOL {
|
|
goto Sixty
|
|
}
|
|
STR = ZR*S1R - ZI*S1I
|
|
STI = ZR*S1I + ZI*S1R
|
|
CC = C1 / (1.0E0 + FID)
|
|
AIR = AIR + CC*(STR*ZR-STI*ZI)
|
|
AII = AII + CC*(STR*ZI+STI*ZR)
|
|
|
|
Sixty:
|
|
if KODE == 1 {
|
|
return
|
|
}
|
|
tmp = cmplx.Sqrt(complex(ZR, ZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
ZTAR = TTH * (ZR*STR - ZI*STI)
|
|
ZTAI = TTH * (ZR*STI + ZI*STR)
|
|
tmp = cmplx.Exp(complex(ZTAR, ZTAI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
PTR = STR*AIR - STI*AII
|
|
AII = STR*AII + STI*AIR
|
|
AIR = PTR
|
|
return
|
|
|
|
// CASE FOR CABS(Z)>1.0.
|
|
Seventy:
|
|
FNU = (1.0E0 + FID) / 3.0E0
|
|
|
|
/*
|
|
SET PARAMETERS RELATED TO MACHINE CONSTANTS.
|
|
TOL IS THE APPROXIMATE UNIT ROUNDOFF LIMITED TO 1.0D-18.
|
|
ELIM IS THE APPROXIMATE EXPONENTIAL OVER-&&UNDERFLOW LIMIT.
|
|
EXP(-ELIM)<EXP(-ALIM)=EXP(-ELIM)/TOL AND
|
|
EXP(ELIM)>EXP(ALIM)=EXP(ELIM)*TOL ARE INTERVALS NEAR
|
|
UNDERFLOW&&OVERFLOW LIMITS WHERE SCALED ARITHMETIC IS DONE.
|
|
RL IS THE LOWER BOUNDARY OF THE ASYMPTOTIC EXPANSION FOR LA>=Z.
|
|
DIG = NUMBER OF BASE 10 DIGITS IN TOL = 10**(-DIG).
|
|
*/
|
|
K1 = imach[15]
|
|
K2 = imach[16]
|
|
R1M5 = dmach[5]
|
|
|
|
K = min(abs(K1), abs(K2))
|
|
ELIM = 2.303E0 * (float64(K)*R1M5 - 3.0E0)
|
|
K1 = imach[14] - 1
|
|
AA = R1M5 * float64(K1)
|
|
DIG = math.Min(AA, 18.0E0)
|
|
AA = AA * 2.303E0
|
|
ALIM = ELIM + math.Max(-AA, -41.45E0)
|
|
RL = 1.2E0*DIG + 3.0E0
|
|
ALAZ = math.Log(AZ)
|
|
|
|
// TEST FOR PROPER RANGE.
|
|
AA = 0.5E0 / TOL
|
|
BB = float64(float32(imach[9])) * 0.5E0
|
|
AA = math.Min(AA, BB)
|
|
AA = math.Pow(AA, TTH)
|
|
if AZ > AA {
|
|
goto TwoSixty
|
|
}
|
|
AA = math.Sqrt(AA)
|
|
if AZ > AA {
|
|
IERR = 3
|
|
}
|
|
tmp = cmplx.Sqrt(complex(ZR, ZI))
|
|
CSQR = real(tmp)
|
|
CSQI = imag(tmp)
|
|
ZTAR = TTH * (ZR*CSQR - ZI*CSQI)
|
|
ZTAI = TTH * (ZR*CSQI + ZI*CSQR)
|
|
|
|
// RE(ZTA)<=0 WHEN RE(Z)<0, ESPECIALLY WHEN IM(Z) IS SMALL.
|
|
IFLAG = 0
|
|
SFAC = 1.0E0
|
|
AK = ZTAI
|
|
if ZR >= 0.0E0 {
|
|
goto Eighty
|
|
}
|
|
BK = ZTAR
|
|
CK = -math.Abs(BK)
|
|
ZTAR = CK
|
|
ZTAI = AK
|
|
|
|
Eighty:
|
|
if ZI != 0.0E0 {
|
|
goto Ninety
|
|
}
|
|
if ZR > 0.0E0 {
|
|
goto Ninety
|
|
}
|
|
ZTAR = 0.0E0
|
|
ZTAI = AK
|
|
Ninety:
|
|
AA = ZTAR
|
|
if AA >= 0.0E0 && ZR > 0.0E0 {
|
|
goto OneTen
|
|
}
|
|
if KODE == 2 {
|
|
goto OneHundred
|
|
}
|
|
|
|
// OVERFLOW TEST.
|
|
if AA > (-ALIM) {
|
|
goto OneHundred
|
|
}
|
|
AA = -AA + 0.25E0*ALAZ
|
|
IFLAG = 1
|
|
SFAC = TOL
|
|
if AA > ELIM {
|
|
goto TwoSeventy
|
|
}
|
|
|
|
OneHundred:
|
|
// CBKNU AND CACON return EXP(ZTA)*K(FNU,ZTA) ON KODE=2.
|
|
MR = 1
|
|
if ZI < 0.0E0 {
|
|
MR = -1
|
|
}
|
|
ZTAR, ZTAI, FNU, KODE, MR, _, CYR, CYI, NN, RL, TOL, ELIM, ALIM = Zacai(ZTAR, ZTAI, FNU, KODE, MR, 1, CYR, CYI, NN, RL, TOL, ELIM, ALIM)
|
|
if NN < 0 {
|
|
goto TwoEighty
|
|
}
|
|
NZ = NZ + NN
|
|
goto OneThirty
|
|
|
|
OneTen:
|
|
if KODE == 2 {
|
|
goto OneTwenty
|
|
}
|
|
|
|
// UNDERFLOW TEST.
|
|
if AA < ALIM {
|
|
goto OneTwenty
|
|
}
|
|
AA = -AA - 0.25E0*ALAZ
|
|
IFLAG = 2
|
|
SFAC = 1.0E0 / TOL
|
|
if AA < (-ELIM) {
|
|
goto TwoTen
|
|
}
|
|
OneTwenty:
|
|
ZTAR, ZTAI, FNU, KODE, _, CYR, CYI, NZ, TOL, ELIM, ALIM = Zbknu(ZTAR, ZTAI, FNU, KODE, 1, CYR, CYI, NZ, TOL, ELIM, ALIM)
|
|
|
|
OneThirty:
|
|
S1R = CYR[1] * COEF
|
|
S1I = CYI[1] * COEF
|
|
if IFLAG != 0 {
|
|
goto OneFifty
|
|
}
|
|
if ID == 1 {
|
|
goto OneFourty
|
|
}
|
|
AIR = CSQR*S1R - CSQI*S1I
|
|
AII = CSQR*S1I + CSQI*S1R
|
|
return
|
|
OneFourty:
|
|
AIR = -(ZR*S1R - ZI*S1I)
|
|
AII = -(ZR*S1I + ZI*S1R)
|
|
return
|
|
OneFifty:
|
|
S1R = S1R * SFAC
|
|
S1I = S1I * SFAC
|
|
if ID == 1 {
|
|
goto OneSixty
|
|
}
|
|
STR = S1R*CSQR - S1I*CSQI
|
|
S1I = S1R*CSQI + S1I*CSQR
|
|
S1R = STR
|
|
AIR = S1R / SFAC
|
|
AII = S1I / SFAC
|
|
return
|
|
OneSixty:
|
|
STR = -(S1R*ZR - S1I*ZI)
|
|
S1I = -(S1R*ZI + S1I*ZR)
|
|
S1R = STR
|
|
AIR = S1R / SFAC
|
|
AII = S1I / SFAC
|
|
return
|
|
OneSeventy:
|
|
AA = 1.0E+3 * dmach[1]
|
|
S1R = ZEROR
|
|
S1I = ZEROI
|
|
if ID == 1 {
|
|
goto OneNinety
|
|
}
|
|
if AZ <= AA {
|
|
goto OneEighty
|
|
}
|
|
S1R = C2 * ZR
|
|
S1I = C2 * ZI
|
|
OneEighty:
|
|
AIR = C1 - S1R
|
|
AII = -S1I
|
|
return
|
|
OneNinety:
|
|
AIR = -C2
|
|
AII = 0.0E0
|
|
AA = math.Sqrt(AA)
|
|
if AZ <= AA {
|
|
goto TwoHundred
|
|
}
|
|
S1R = 0.5E0 * (ZR*ZR - ZI*ZI)
|
|
S1I = ZR * ZI
|
|
TwoHundred:
|
|
AIR = AIR + C1*S1R
|
|
AII = AII + C1*S1I
|
|
return
|
|
TwoTen:
|
|
NZ = 1
|
|
AIR = ZEROR
|
|
AII = ZEROI
|
|
return
|
|
TwoSeventy:
|
|
NZ = 0
|
|
IERR = 2
|
|
return
|
|
TwoEighty:
|
|
if NN == (-1) {
|
|
goto TwoSeventy
|
|
}
|
|
NZ = 0
|
|
IERR = 5
|
|
return
|
|
TwoSixty:
|
|
IERR = 4
|
|
NZ = 0
|
|
return
|
|
}
|
|
|
|
// sbknu computes the k bessel function in the right half z plane.
|
|
func Zbknu(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL, ELIM, ALIM float64) (ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout, ELIMout, ALIMout float64) {
|
|
/* Old dimension comment.
|
|
DIMENSION YR(N), YI(N), CC(8), CSSR(3), CSRR(3), BRY(3), CYR(2),
|
|
* CYI(2)
|
|
*/
|
|
|
|
// TODO(btracey): Find which of these are inputs/outputs/both and clean up
|
|
// the function call.
|
|
// YR and YI have length n (but n+1 with better indexing)
|
|
var AA, AK, ASCLE, A1, A2, BB, BK, CAZ,
|
|
CBI, CBR, CCHI, CCHR, CKI, CKR, COEFI, COEFR, CONEI, CONER,
|
|
CRSCR, CSCLR, CSHI, CSHR, CSI, CSR, CTWOR,
|
|
CZEROI, CZEROR, CZI, CZR, DNU, DNU2, DPI, ETEST, FC, FHS,
|
|
FI, FK, FKS, FMUI, FMUR, FPI, FR, G1, G2, HPI, PI, PR, PTI,
|
|
PTR, P1I, P1R, P2I, P2M, P2R, QI, QR, RAK, RCAZ, RTHPI, RZI,
|
|
RZR, R1, S, SMUI, SMUR, SPI, STI, STR, S1I, S1R, S2I, S2R, TM,
|
|
TTH, T1, T2, ELM, CELMR, ZDR, ZDI, AS, ALAS, HELIM float64
|
|
|
|
var I, IFLAG, INU, K, KFLAG, KK, KMAX, KODED, IDUM, J, IC, INUB, NW int
|
|
|
|
var sinh, cosh complex128
|
|
//var sin, cos float64
|
|
|
|
var tmp, p complex128
|
|
var CSSR, CSRR, BRY [4]float64
|
|
var CYR, CYI [3]float64
|
|
|
|
KMAX = 30
|
|
CZEROR = 0
|
|
CZEROI = 0
|
|
CONER = 1
|
|
CONEI = 0
|
|
CTWOR = 2
|
|
R1 = 2
|
|
|
|
DPI = 3.14159265358979324E0
|
|
RTHPI = 1.25331413731550025E0
|
|
SPI = 1.90985931710274403E0
|
|
HPI = 1.57079632679489662E0
|
|
FPI = 1.89769999331517738E0
|
|
TTH = 6.66666666666666666E-01
|
|
|
|
CC := [9]float64{math.NaN(), 5.77215664901532861E-01, -4.20026350340952355E-02,
|
|
-4.21977345555443367E-02, 7.21894324666309954E-03,
|
|
-2.15241674114950973E-04, -2.01348547807882387E-05,
|
|
1.13302723198169588E-06, 6.11609510448141582E-09}
|
|
|
|
CAZ = cmplx.Abs(complex(ZR, ZI))
|
|
CSCLR = 1.0E0 / TOL
|
|
CRSCR = TOL
|
|
CSSR[1] = CSCLR
|
|
CSSR[2] = 1.0E0
|
|
CSSR[3] = CRSCR
|
|
CSRR[1] = CRSCR
|
|
CSRR[2] = 1.0E0
|
|
CSRR[3] = CSCLR
|
|
BRY[1] = 1.0E+3 * dmach[1] / TOL
|
|
BRY[2] = 1.0E0 / BRY[1]
|
|
BRY[3] = dmach[2]
|
|
NZ = 0
|
|
IFLAG = 0
|
|
KODED = KODE
|
|
RCAZ = 1.0E0 / CAZ
|
|
STR = ZR * RCAZ
|
|
STI = -ZI * RCAZ
|
|
RZR = (STR + STR) * RCAZ
|
|
RZI = (STI + STI) * RCAZ
|
|
INU = int(float32(FNU + 0.5))
|
|
DNU = FNU - float64(INU)
|
|
if math.Abs(DNU) == 0.5E0 {
|
|
goto OneTen
|
|
}
|
|
DNU2 = 0.0E0
|
|
if math.Abs(DNU) > TOL {
|
|
DNU2 = DNU * DNU
|
|
}
|
|
if CAZ > R1 {
|
|
goto OneTen
|
|
}
|
|
|
|
// SERIES FOR CABS(Z)<=R1.
|
|
FC = 1.0E0
|
|
tmp = cmplx.Log(complex(RZR, RZI))
|
|
SMUR = real(tmp)
|
|
SMUI = imag(tmp)
|
|
FMUR = SMUR * DNU
|
|
FMUI = SMUI * DNU
|
|
tmp = complex(FMUR, FMUI)
|
|
sinh = cmplx.Sinh(tmp)
|
|
cosh = cmplx.Cosh(tmp)
|
|
CSHR = real(sinh)
|
|
CSHI = imag(sinh)
|
|
CCHR = real(cosh)
|
|
CCHI = imag(cosh)
|
|
if DNU == 0.0E0 {
|
|
goto Ten
|
|
}
|
|
FC = DNU * DPI
|
|
FC = FC / math.Sin(FC)
|
|
SMUR = CSHR / DNU
|
|
SMUI = CSHI / DNU
|
|
Ten:
|
|
A2 = 1.0E0 + DNU
|
|
|
|
// GAM(1-Z)*GAM(1+Z)=PI*Z/SIN(PI*Z), T1=1/GAM(1-DNU), T2=1/GAM(1+DNU).
|
|
T2 = math.Exp(-dgamln(A2, IDUM))
|
|
T1 = 1.0E0 / (T2 * FC)
|
|
if math.Abs(DNU) > 0.1E0 {
|
|
goto Forty
|
|
}
|
|
|
|
// SERIES FOR F0 TO RESOLVE INDETERMINACY FOR SMALL ABS(DNU).
|
|
AK = 1.0E0
|
|
S = CC[1]
|
|
for K = 2; K <= 8; K++ {
|
|
AK = AK * DNU2
|
|
TM = CC[K] * AK
|
|
S = S + TM
|
|
if math.Abs(TM) < TOL {
|
|
goto Thirty
|
|
}
|
|
}
|
|
Thirty:
|
|
G1 = -S
|
|
goto Fifty
|
|
Forty:
|
|
G1 = (T1 - T2) / (DNU + DNU)
|
|
Fifty:
|
|
G2 = (T1 + T2) * 0.5E0
|
|
FR = FC * (CCHR*G1 + SMUR*G2)
|
|
FI = FC * (CCHI*G1 + SMUI*G2)
|
|
tmp = cmplx.Exp(complex(FMUR, FMUI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
PR = 0.5E0 * STR / T2
|
|
PI = 0.5E0 * STI / T2
|
|
tmp = complex(0.5, 0) / complex(STR, STI)
|
|
PTR = real(tmp)
|
|
PTI = imag(tmp)
|
|
QR = PTR / T1
|
|
QI = PTI / T1
|
|
S1R = FR
|
|
S1I = FI
|
|
S2R = PR
|
|
S2I = PI
|
|
AK = 1.0E0
|
|
A1 = 1.0E0
|
|
CKR = CONER
|
|
CKI = CONEI
|
|
BK = 1.0E0 - DNU2
|
|
if INU > 0 || N > 1 {
|
|
goto Eighty
|
|
}
|
|
|
|
// GENERATE K(FNU,Z), 0.0E0 <= FNU < 0.5E0 AND N=1.
|
|
if CAZ < TOL {
|
|
goto Seventy
|
|
}
|
|
tmp = complex(ZR, ZI) * complex(ZR, ZI)
|
|
CZR = real(tmp)
|
|
CZI = imag(tmp)
|
|
CZR = 0.25E0 * CZR
|
|
CZI = 0.25E0 * CZI
|
|
T1 = 0.25E0 * CAZ * CAZ
|
|
Sixty:
|
|
FR = (FR*AK + PR + QR) / BK
|
|
FI = (FI*AK + PI + QI) / BK
|
|
STR = 1.0E0 / (AK - DNU)
|
|
PR = PR * STR
|
|
PI = PI * STR
|
|
STR = 1.0E0 / (AK + DNU)
|
|
QR = QR * STR
|
|
QI = QI * STR
|
|
STR = CKR*CZR - CKI*CZI
|
|
RAK = 1.0E0 / AK
|
|
CKI = (CKR*CZI + CKI*CZR) * RAK
|
|
CKR = STR * RAK
|
|
S1R = CKR*FR - CKI*FI + S1R
|
|
S1I = CKR*FI + CKI*FR + S1I
|
|
A1 = A1 * T1 * RAK
|
|
BK = BK + AK + AK + 1.0E0
|
|
AK = AK + 1.0E0
|
|
if A1 > TOL {
|
|
goto Sixty
|
|
}
|
|
Seventy:
|
|
YR[1] = S1R
|
|
YI[1] = S1I
|
|
if KODED == 1 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
tmp = cmplx.Exp(complex(ZR, ZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
tmp = complex(S1R, S1I) * complex(STR, STI)
|
|
YR[1] = real(tmp)
|
|
YI[1] = imag(tmp)
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
|
|
// GENERATE K(DNU,Z) AND K(DNU+1,Z) FOR FORWARD RECURRENCE.
|
|
Eighty:
|
|
if CAZ < TOL {
|
|
goto OneHundred
|
|
}
|
|
tmp = complex(ZR, ZI) * complex(ZR, ZI)
|
|
CZR = real(tmp)
|
|
CZI = imag(tmp)
|
|
CZR = 0.25E0 * CZR
|
|
CZI = 0.25E0 * CZI
|
|
T1 = 0.25E0 * CAZ * CAZ
|
|
Ninety:
|
|
FR = (FR*AK + PR + QR) / BK
|
|
FI = (FI*AK + PI + QI) / BK
|
|
STR = 1.0E0 / (AK - DNU)
|
|
PR = PR * STR
|
|
PI = PI * STR
|
|
STR = 1.0E0 / (AK + DNU)
|
|
QR = QR * STR
|
|
QI = QI * STR
|
|
STR = CKR*CZR - CKI*CZI
|
|
RAK = 1.0E0 / AK
|
|
CKI = (CKR*CZI + CKI*CZR) * RAK
|
|
CKR = STR * RAK
|
|
S1R = CKR*FR - CKI*FI + S1R
|
|
S1I = CKR*FI + CKI*FR + S1I
|
|
STR = PR - FR*AK
|
|
STI = PI - FI*AK
|
|
S2R = CKR*STR - CKI*STI + S2R
|
|
S2I = CKR*STI + CKI*STR + S2I
|
|
A1 = A1 * T1 * RAK
|
|
BK = BK + AK + AK + 1.0E0
|
|
AK = AK + 1.0E0
|
|
if A1 > TOL {
|
|
goto Ninety
|
|
}
|
|
OneHundred:
|
|
KFLAG = 2
|
|
A1 = FNU + 1.0E0
|
|
AK = A1 * math.Abs(SMUR)
|
|
if AK > ALIM {
|
|
KFLAG = 3
|
|
}
|
|
STR = CSSR[KFLAG]
|
|
P2R = S2R * STR
|
|
P2I = S2I * STR
|
|
tmp = complex(P2R, P2I) * complex(RZR, RZI)
|
|
S2R = real(tmp)
|
|
S2I = imag(tmp)
|
|
S1R = S1R * STR
|
|
S1I = S1I * STR
|
|
if KODED == 1 {
|
|
goto TwoTen
|
|
}
|
|
tmp = cmplx.Exp(complex(ZR, ZI))
|
|
FR = real(tmp)
|
|
FI = imag(tmp)
|
|
tmp = complex(S1R, S1I) * complex(FR, FI)
|
|
S1R = real(tmp)
|
|
S1I = imag(tmp)
|
|
tmp = complex(S2R, S2I) * complex(FR, FI)
|
|
S2R = real(tmp)
|
|
S2I = imag(tmp)
|
|
goto TwoTen
|
|
|
|
// IFLAG=0 MEANS NO UNDERFLOW OCCURRED
|
|
// IFLAG=1 MEANS AN UNDERFLOW OCCURRED- COMPUTATION PROCEEDS WITH
|
|
// KODED=2 AND A TEST FOR ON SCALE VALUES IS MADE DURING FORWARD RECURSION
|
|
OneTen:
|
|
tmp = cmplx.Sqrt(complex(ZR, ZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
tmp = complex(RTHPI, CZEROI) / complex(STR, STI)
|
|
COEFR = real(tmp)
|
|
COEFI = imag(tmp)
|
|
KFLAG = 2
|
|
if KODED == 2 {
|
|
goto OneTwenty
|
|
}
|
|
if ZR > ALIM {
|
|
goto TwoNinety
|
|
}
|
|
|
|
STR = math.Exp(-ZR) * CSSR[KFLAG]
|
|
//sin, cos = math.Sincos(ZI)
|
|
STI = -STR * math.Sin(ZI)
|
|
STR = STR * math.Cos(ZI)
|
|
tmp = complex(COEFR, COEFI) * complex(STR, STI)
|
|
COEFR = real(tmp)
|
|
COEFI = imag(tmp)
|
|
OneTwenty:
|
|
if math.Abs(DNU) == 0.5E0 {
|
|
goto ThreeHundred
|
|
}
|
|
// MILLER ALGORITHM FOR CABS(Z)>R1.
|
|
AK = math.Cos(DPI * DNU)
|
|
AK = math.Abs(AK)
|
|
if AK == CZEROR {
|
|
goto ThreeHundred
|
|
}
|
|
FHS = math.Abs(0.25E0 - DNU2)
|
|
if FHS == CZEROR {
|
|
goto ThreeHundred
|
|
}
|
|
|
|
// COMPUTE R2=F(E). if CABS(Z)>=R2, USE FORWARD RECURRENCE TO
|
|
// DETERMINE THE BACKWARD INDEX K. R2=F(E) IS A STRAIGHT LINE ON
|
|
// 12<=E<=60. E IS COMPUTED FROM 2**(-E)=B**(1-I1MACH(14))=
|
|
// TOL WHERE B IS THE BASE OF THE ARITHMETIC.
|
|
T1 = float64(imach[14] - 1)
|
|
T1 = T1 * dmach[5] * 3.321928094E0
|
|
T1 = math.Max(T1, 12.0E0)
|
|
T1 = math.Min(T1, 60.0E0)
|
|
T2 = TTH*T1 - 6.0E0
|
|
if ZR != 0.0E0 {
|
|
goto OneThirty
|
|
}
|
|
T1 = HPI
|
|
goto OneFourty
|
|
OneThirty:
|
|
T1 = math.Atan(ZI / ZR)
|
|
T1 = math.Abs(T1)
|
|
OneFourty:
|
|
if T2 > CAZ {
|
|
goto OneSeventy
|
|
}
|
|
// FORWARD RECURRENCE LOOP WHEN CABS(Z)>=R2.
|
|
ETEST = AK / (DPI * CAZ * TOL)
|
|
FK = CONER
|
|
if ETEST < CONER {
|
|
goto OneEighty
|
|
}
|
|
FKS = CTWOR
|
|
CKR = CAZ + CAZ + CTWOR
|
|
P1R = CZEROR
|
|
P2R = CONER
|
|
for I = 1; I <= KMAX; I++ {
|
|
AK = FHS / FKS
|
|
CBR = CKR / (FK + CONER)
|
|
PTR = P2R
|
|
P2R = CBR*P2R - P1R*AK
|
|
P1R = PTR
|
|
CKR = CKR + CTWOR
|
|
FKS = FKS + FK + FK + CTWOR
|
|
FHS = FHS + FK + FK
|
|
FK = FK + CONER
|
|
STR = math.Abs(P2R) * FK
|
|
if ETEST < STR {
|
|
goto OneSixty
|
|
}
|
|
}
|
|
goto ThreeTen
|
|
OneSixty:
|
|
FK = FK + SPI*T1*math.Sqrt(T2/CAZ)
|
|
FHS = math.Abs(0.25 - DNU2)
|
|
goto OneEighty
|
|
OneSeventy:
|
|
// COMPUTE BACKWARD INDEX K FOR CABS(Z)<R2.
|
|
A2 = math.Sqrt(CAZ)
|
|
AK = FPI * AK / (TOL * math.Sqrt(A2))
|
|
AA = 3.0E0 * T1 / (1.0E0 + CAZ)
|
|
BB = 14.7E0 * T1 / (28.0E0 + CAZ)
|
|
AK = (math.Log(AK) + CAZ*math.Cos(AA)/(1.0E0+0.008E0*CAZ)) / math.Cos(BB)
|
|
FK = 0.12125E0*AK*AK/CAZ + 1.5E0
|
|
OneEighty:
|
|
// BACKWARD RECURRENCE LOOP FOR MILLER ALGORITHM.
|
|
K = int(float32(FK))
|
|
FK = float64(K)
|
|
FKS = FK * FK
|
|
P1R = CZEROR
|
|
P1I = CZEROI
|
|
P2R = TOL
|
|
P2I = CZEROI
|
|
CSR = P2R
|
|
CSI = P2I
|
|
for I = 1; I <= K; I++ {
|
|
A1 = FKS - FK
|
|
AK = (FKS + FK) / (A1 + FHS)
|
|
RAK = 2.0E0 / (FK + CONER)
|
|
CBR = (FK + ZR) * RAK
|
|
CBI = ZI * RAK
|
|
PTR = P2R
|
|
PTI = P2I
|
|
P2R = (PTR*CBR - PTI*CBI - P1R) * AK
|
|
P2I = (PTI*CBR + PTR*CBI - P1I) * AK
|
|
P1R = PTR
|
|
P1I = PTI
|
|
CSR = CSR + P2R
|
|
CSI = CSI + P2I
|
|
FKS = A1 - FK + CONER
|
|
FK = FK - CONER
|
|
}
|
|
// COMPUTE (P2/CS)=(P2/CABS(CS))*(CONJG(CS)/CABS(CS)) FOR BETTER SCALING.
|
|
TM = cmplx.Abs(complex(CSR, CSI))
|
|
PTR = 1.0E0 / TM
|
|
S1R = P2R * PTR
|
|
S1I = P2I * PTR
|
|
CSR = CSR * PTR
|
|
CSI = -CSI * PTR
|
|
tmp = complex(COEFR, COEFI) * complex(S1R, S1I)
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
tmp = complex(STR, STI) * complex(CSR, CSI)
|
|
S1R = real(tmp)
|
|
S1I = imag(tmp)
|
|
if INU > 0 || N > 1 {
|
|
goto TwoHundred
|
|
}
|
|
ZDR = ZR
|
|
ZDI = ZI
|
|
if IFLAG == 1 {
|
|
goto TwoSeventy
|
|
}
|
|
goto TwoFourty
|
|
TwoHundred:
|
|
// COMPUTE P1/P2=(P1/CABS(P2)*CONJG(P2)/CABS(P2) FOR SCALING.
|
|
TM = cmplx.Abs(complex(P2R, P2I))
|
|
PTR = 1.0E0 / TM
|
|
P1R = P1R * PTR
|
|
P1I = P1I * PTR
|
|
P2R = P2R * PTR
|
|
P2I = -P2I * PTR
|
|
tmp = complex(P1R, P1I) * complex(P2R, P2I)
|
|
PTR = real(tmp)
|
|
PTI = imag(tmp)
|
|
STR = DNU + 0.5E0 - PTR
|
|
STI = -PTI
|
|
tmp = complex(STR, STI) / complex(ZR, ZI)
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
STR = STR + 1.0E0
|
|
tmp = complex(STR, STI) * complex(S1R, S1I)
|
|
S2R = real(tmp)
|
|
S2I = imag(tmp)
|
|
|
|
// FORWARD RECURSION ON THE THREE TERM RECURSION WITH RELATION WITH
|
|
// SCALING NEAR EXPONENT EXTREMES ON KFLAG=1 OR KFLAG=3
|
|
TwoTen:
|
|
STR = DNU + 1.0E0
|
|
CKR = STR * RZR
|
|
CKI = STR * RZI
|
|
if N == 1 {
|
|
INU = INU - 1
|
|
}
|
|
if INU > 0 {
|
|
goto TwoTwenty
|
|
}
|
|
if N > 1 {
|
|
goto TwoFifteen
|
|
}
|
|
S1R = S2R
|
|
S1I = S2I
|
|
TwoFifteen:
|
|
ZDR = ZR
|
|
ZDI = ZI
|
|
if IFLAG == 1 {
|
|
goto TwoSeventy
|
|
}
|
|
goto TwoFourty
|
|
TwoTwenty:
|
|
INUB = 1
|
|
if IFLAG == 1 {
|
|
goto TwoSixtyOne
|
|
}
|
|
TwoTwentyFive:
|
|
P1R = CSRR[KFLAG]
|
|
ASCLE = BRY[KFLAG]
|
|
for I = INUB; I <= INU; I++ {
|
|
STR = S2R
|
|
STI = S2I
|
|
S2R = CKR*STR - CKI*STI + S1R
|
|
S2I = CKR*STI + CKI*STR + S1I
|
|
S1R = STR
|
|
S1I = STI
|
|
CKR = CKR + RZR
|
|
CKI = CKI + RZI
|
|
if KFLAG >= 3 {
|
|
continue
|
|
}
|
|
P2R = S2R * P1R
|
|
P2I = S2I * P1R
|
|
STR = math.Abs(P2R)
|
|
STI = math.Abs(P2I)
|
|
P2M = math.Max(STR, STI)
|
|
if P2M <= ASCLE {
|
|
continue
|
|
}
|
|
KFLAG = KFLAG + 1
|
|
ASCLE = BRY[KFLAG]
|
|
S1R = S1R * P1R
|
|
S1I = S1I * P1R
|
|
S2R = P2R
|
|
S2I = P2I
|
|
STR = CSSR[KFLAG]
|
|
S1R = S1R * STR
|
|
S1I = S1I * STR
|
|
S2R = S2R * STR
|
|
S2I = S2I * STR
|
|
P1R = CSRR[KFLAG]
|
|
}
|
|
if N != 1 {
|
|
goto TwoFourty
|
|
}
|
|
S1R = S2R
|
|
S1I = S2I
|
|
TwoFourty:
|
|
STR = CSRR[KFLAG]
|
|
YR[1] = S1R * STR
|
|
YI[1] = S1I * STR
|
|
if N == 1 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
YR[2] = S2R * STR
|
|
YI[2] = S2I * STR
|
|
if N == 2 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
KK = 2
|
|
TwoFifty:
|
|
KK = KK + 1
|
|
if KK > N {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
P1R = CSRR[KFLAG]
|
|
ASCLE = BRY[KFLAG]
|
|
for I = KK; I <= N; I++ {
|
|
P2R = S2R
|
|
P2I = S2I
|
|
S2R = CKR*P2R - CKI*P2I + S1R
|
|
S2I = CKI*P2R + CKR*P2I + S1I
|
|
S1R = P2R
|
|
S1I = P2I
|
|
CKR = CKR + RZR
|
|
CKI = CKI + RZI
|
|
P2R = S2R * P1R
|
|
P2I = S2I * P1R
|
|
YR[I] = P2R
|
|
YI[I] = P2I
|
|
if KFLAG >= 3 {
|
|
continue
|
|
}
|
|
STR = math.Abs(P2R)
|
|
STI = math.Abs(P2I)
|
|
P2M = math.Max(STR, STI)
|
|
if P2M <= ASCLE {
|
|
continue
|
|
}
|
|
KFLAG = KFLAG + 1
|
|
ASCLE = BRY[KFLAG]
|
|
S1R = S1R * P1R
|
|
S1I = S1I * P1R
|
|
S2R = P2R
|
|
S2I = P2I
|
|
STR = CSSR[KFLAG]
|
|
S1R = S1R * STR
|
|
S1I = S1I * STR
|
|
S2R = S2R * STR
|
|
S2I = S2I * STR
|
|
P1R = CSRR[KFLAG]
|
|
}
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
|
|
// IFLAG=1 CASES, FORWARD RECURRENCE ON SCALED VALUES ON UNDERFLOW.
|
|
TwoSixtyOne:
|
|
HELIM = 0.5E0 * ELIM
|
|
ELM = math.Exp(-ELIM)
|
|
CELMR = ELM
|
|
ASCLE = BRY[1]
|
|
ZDR = ZR
|
|
ZDI = ZI
|
|
IC = -1
|
|
J = 2
|
|
for I = 1; I <= INU; I++ {
|
|
STR = S2R
|
|
STI = S2I
|
|
S2R = STR*CKR - STI*CKI + S1R
|
|
S2I = STI*CKR + STR*CKI + S1I
|
|
S1R = STR
|
|
S1I = STI
|
|
CKR = CKR + RZR
|
|
CKI = CKI + RZI
|
|
AS = cmplx.Abs(complex(S2R, S2I))
|
|
ALAS = math.Log(AS)
|
|
P2R = -ZDR + ALAS
|
|
if P2R < (-ELIM) {
|
|
goto TwoSixtyThree
|
|
}
|
|
tmp = cmplx.Log(complex(S2R, S2I))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
P2R = -ZDR + STR
|
|
P2I = -ZDI + STI
|
|
P2M = math.Exp(P2R) / TOL
|
|
// sin, cos = math.Sincos(P2I)
|
|
P1R = P2M * math.Cos(P2I)
|
|
P1I = P2M * math.Sin(P2I)
|
|
p = complex(P1R, P1I)
|
|
NW = Zuchk(p, ASCLE, TOL)
|
|
if NW != 0 {
|
|
goto TwoSixtyThree
|
|
}
|
|
J = 3 - J
|
|
CYR[J] = P1R
|
|
CYI[J] = P1I
|
|
if IC == (I - 1) {
|
|
goto TwoSixtyFour
|
|
}
|
|
IC = I
|
|
continue
|
|
TwoSixtyThree:
|
|
if ALAS < HELIM {
|
|
continue
|
|
}
|
|
ZDR = ZDR - ELIM
|
|
S1R = S1R * CELMR
|
|
S1I = S1I * CELMR
|
|
S2R = S2R * CELMR
|
|
S2I = S2I * CELMR
|
|
}
|
|
if N != 1 {
|
|
goto TwoSeventy
|
|
}
|
|
S1R = S2R
|
|
S1I = S2I
|
|
goto TwoSeventy
|
|
TwoSixtyFour:
|
|
KFLAG = 1
|
|
INUB = I + 1
|
|
S2R = CYR[J]
|
|
S2I = CYI[J]
|
|
J = 3 - J
|
|
S1R = CYR[J]
|
|
S1I = CYI[J]
|
|
if INUB <= INU {
|
|
goto TwoTwentyFive
|
|
}
|
|
if N != 1 {
|
|
goto TwoFourty
|
|
}
|
|
S1R = S2R
|
|
S1I = S2I
|
|
goto TwoFourty
|
|
TwoSeventy:
|
|
YR[1] = S1R
|
|
YI[1] = S1I
|
|
if N == 1 {
|
|
goto TwoEighty
|
|
}
|
|
YR[2] = S2R
|
|
YI[2] = S2I
|
|
TwoEighty:
|
|
ASCLE = BRY[1]
|
|
ZDR, ZDI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM = Zkscl(ZDR, ZDI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM)
|
|
INU = N - NZ
|
|
if INU <= 0 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
KK = NZ + 1
|
|
S1R = YR[KK]
|
|
S1I = YI[KK]
|
|
YR[KK] = S1R * CSRR[1]
|
|
YI[KK] = S1I * CSRR[1]
|
|
if INU == 1 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
KK = NZ + 2
|
|
S2R = YR[KK]
|
|
S2I = YI[KK]
|
|
YR[KK] = S2R * CSRR[1]
|
|
YI[KK] = S2I * CSRR[1]
|
|
if INU == 2 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
T2 = FNU + float64(float32(KK-1))
|
|
CKR = T2 * RZR
|
|
CKI = T2 * RZI
|
|
KFLAG = 1
|
|
goto TwoFifty
|
|
TwoNinety:
|
|
|
|
// SCALE BY math.Exp(Z), IFLAG = 1 CASES.
|
|
|
|
KODED = 2
|
|
IFLAG = 1
|
|
KFLAG = 2
|
|
goto OneTwenty
|
|
|
|
// FNU=HALF ODD INTEGER CASE, DNU=-0.5
|
|
ThreeHundred:
|
|
S1R = COEFR
|
|
S1I = COEFI
|
|
S2R = COEFR
|
|
S2I = COEFI
|
|
goto TwoTen
|
|
|
|
ThreeTen:
|
|
NZ = -2
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL, ELIM, ALIM
|
|
}
|
|
|
|
// SET K FUNCTIONS TO ZERO ON UNDERFLOW, CONTINUE RECURRENCE
|
|
// ON SCALED FUNCTIONS UNTIL TWO MEMBERS COME ON SCALE, THEN
|
|
// return WITH MIN(NZ+2,N) VALUES SCALED BY 1/TOL.
|
|
func Zkscl(ZRR, ZRI, FNU float64, N int, YR, YI []float64, NZ int, RZR, RZI, ASCLE, TOL, ELIM float64) (
|
|
ZRRout, ZRIout, FNUout float64, Nout int, YRout, YIout []float64, NZout int, RZRout, RZIout, ASCLEout, TOLout, ELIMout float64) {
|
|
var ACS, AS, CKI, CKR, CSI, CSR, FN, STR, S1I, S1R, S2I,
|
|
S2R, ZEROI, ZEROR, ZDR, ZDI, CELMR, ELM, HELIM, ALAS float64
|
|
|
|
var I, IC, KK, NN, NW int
|
|
var tmp, c complex128
|
|
var CYR, CYI [3]float64
|
|
var sin, cos float64
|
|
|
|
// DIMENSION YR(N), YI(N), CYR(2), CYI(2)
|
|
ZEROR = 0
|
|
ZEROI = 0
|
|
NZ = 0
|
|
IC = 0
|
|
NN = min(2, N)
|
|
for I = 1; I <= NN; I++ {
|
|
S1R = YR[I]
|
|
S1I = YI[I]
|
|
CYR[I] = S1R
|
|
CYI[I] = S1I
|
|
AS = cmplx.Abs(complex(S1R, S1I))
|
|
ACS = -ZRR + math.Log(AS)
|
|
NZ = NZ + 1
|
|
YR[I] = ZEROR
|
|
YI[I] = ZEROI
|
|
if ACS < (-ELIM) {
|
|
continue
|
|
}
|
|
|
|
tmp = cmplx.Log(complex(S1R, S1I))
|
|
CSR = real(tmp)
|
|
CSI = imag(tmp)
|
|
CSR = CSR - ZRR
|
|
CSI = CSI - ZRI
|
|
STR = math.Exp(CSR) / TOL
|
|
// sin, cos = math.Sincos(CSI)
|
|
CSR = STR * math.Cos(CSI)
|
|
CSI = STR * math.Sin(CSI)
|
|
c = complex(CSR, CSI)
|
|
NW = Zuchk(c, ASCLE, TOL)
|
|
if NW != 0 {
|
|
continue
|
|
}
|
|
YR[I] = CSR
|
|
YI[I] = CSI
|
|
IC = I
|
|
NZ = NZ - 1
|
|
}
|
|
if N == 1 {
|
|
return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM
|
|
}
|
|
if IC > 1 {
|
|
goto Twenty
|
|
}
|
|
YR[1] = ZEROR
|
|
YI[1] = ZEROI
|
|
NZ = 2
|
|
Twenty:
|
|
if N == 2 {
|
|
return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM
|
|
}
|
|
if NZ == 0 {
|
|
return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM
|
|
}
|
|
FN = FNU + 1.0E0
|
|
CKR = FN * RZR
|
|
CKI = FN * RZI
|
|
S1R = CYR[1]
|
|
S1I = CYI[1]
|
|
S2R = CYR[2]
|
|
S2I = CYI[2]
|
|
HELIM = 0.5E0 * ELIM
|
|
ELM = math.Exp(-ELIM)
|
|
CELMR = ELM
|
|
ZDR = ZRR
|
|
ZDI = ZRI
|
|
|
|
// FIND TWO CONSECUTIVE Y VALUES ON SCALE. SCALE RECURRENCE IF
|
|
// S2 GETS LARGER THAN EXP(ELIM/2)
|
|
for I = 3; I <= N; I++ {
|
|
KK = I
|
|
CSR = S2R
|
|
CSI = S2I
|
|
S2R = CKR*CSR - CKI*CSI + S1R
|
|
S2I = CKI*CSR + CKR*CSI + S1I
|
|
S1R = CSR
|
|
S1I = CSI
|
|
CKR = CKR + RZR
|
|
CKI = CKI + RZI
|
|
AS = cmplx.Abs(complex(S2R, S2I))
|
|
ALAS = math.Log(AS)
|
|
ACS = -ZDR + ALAS
|
|
NZ = NZ + 1
|
|
YR[I] = ZEROR
|
|
YI[I] = ZEROI
|
|
if ACS < (-ELIM) {
|
|
goto TwentyFive
|
|
}
|
|
tmp = cmplx.Log(complex(S2R, S2I))
|
|
CSR = real(tmp)
|
|
CSI = imag(tmp)
|
|
CSR = CSR - ZDR
|
|
CSI = CSI - ZDI
|
|
STR = math.Exp(CSR) / TOL
|
|
sin, cos = math.Sincos(CSI)
|
|
CSR = STR * cos
|
|
CSI = STR * sin
|
|
c = complex(CSR, CSI)
|
|
NW = Zuchk(c, ASCLE, TOL)
|
|
if NW != 0 {
|
|
goto TwentyFive
|
|
}
|
|
YR[I] = CSR
|
|
YI[I] = CSI
|
|
NZ = NZ - 1
|
|
if IC == KK-1 {
|
|
goto Forty
|
|
}
|
|
IC = KK
|
|
continue
|
|
TwentyFive:
|
|
if ALAS < HELIM {
|
|
continue
|
|
}
|
|
ZDR = ZDR - ELIM
|
|
S1R = S1R * CELMR
|
|
S1I = S1I * CELMR
|
|
S2R = S2R * CELMR
|
|
S2I = S2I * CELMR
|
|
}
|
|
NZ = N
|
|
if IC == N {
|
|
NZ = N - 1
|
|
}
|
|
goto FourtyFive
|
|
Forty:
|
|
NZ = KK - 2
|
|
FourtyFive:
|
|
for I = 1; I <= NZ; I++ {
|
|
YR[I] = ZEROR
|
|
YI[I] = ZEROI
|
|
}
|
|
return ZRR, ZRI, FNU, N, YR, YI, NZ, RZR, RZI, ASCLE, TOL, ELIM
|
|
}
|
|
|
|
// Zuchk tests whether the magnitude of the real or imaginary part would
|
|
// underflow when y is scaled by tol.
|
|
//
|
|
// y enters as a scaled quantity whose magnitude is greater than
|
|
// 1e3 + 3*dmach(1)/tol
|
|
// y is accepted if the underflow is at least one precision below the magnitude
|
|
// of the largest component. Otherwise an underflow is assumed as the phase angle
|
|
// does not have sufficient accuracy.
|
|
func Zuchk(y complex128, scale, tol float64) int {
|
|
absR := math.Abs(real(y))
|
|
absI := math.Abs(imag(y))
|
|
minAbs := math.Min(absR, absI)
|
|
if minAbs > scale {
|
|
return 0
|
|
}
|
|
maxAbs := math.Max(absR, absI)
|
|
minAbs /= tol
|
|
if maxAbs < minAbs {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ZACAI APPLIES THE ANALYTIC CONTINUATION FORMULA
|
|
//
|
|
// K(FNU,ZN*EXP(MP))=K(FNU,ZN)*EXP(-MP*FNU) - MP*I(FNU,ZN)
|
|
// MP=PI*MR*CMPLX(0.0,1.0)
|
|
//
|
|
// TO CONTINUE THE K FUNCTION FROM THE RIGHT HALF TO THE LEFT
|
|
// HALF Z PLANE FOR USE WITH ZAIRY WHERE FNU=1/3 OR 2/3 AND N=1.
|
|
// ZACAI IS THE SAME AS ZACON WITH THE PARTS FOR LARGER ORDERS AND
|
|
// RECURRENCE REMOVED. A RECURSIVE CALL TO ZACON CAN RESULT if ZACON
|
|
// IS CALLED FROM ZAIRY.
|
|
func Zacai(ZR, ZI, FNU float64, KODE, MR, N int, YR, YI []float64, NZ int, RL, TOL, ELIM, ALIM float64) (
|
|
ZRout, ZIout, FNUout float64, KODEout, MRout, Nout int, YRout, YIout []float64, NZout int, RLout, TOLout, ELIMout, ALIMout float64) {
|
|
var ARG, ASCLE, AZ, CSGNR, CSGNI, CSPNR,
|
|
CSPNI, C1R, C1I, C2R, C2I, DFNU, FMR, PI,
|
|
SGN, YY, ZNR, ZNI float64
|
|
var INU, IUF, NN, NW int
|
|
var zn, c1, c2, z complex128
|
|
var y []complex128
|
|
//var sin, cos float64
|
|
|
|
CYR := []float64{math.NaN(), 0, 0}
|
|
CYI := []float64{math.NaN(), 0, 0}
|
|
|
|
PI = math.Pi
|
|
NZ = 0
|
|
ZNR = -ZR
|
|
ZNI = -ZI
|
|
AZ = cmplx.Abs(complex(ZR, ZI))
|
|
NN = N
|
|
DFNU = FNU + float64(float32(N-1))
|
|
if AZ <= 2.0E0 {
|
|
goto Ten
|
|
}
|
|
if AZ*AZ*0.25 > DFNU+1.0E0 {
|
|
goto Twenty
|
|
}
|
|
Ten:
|
|
// POWER SERIES FOR THE I FUNCTION.
|
|
z = complex(ZNR, ZNI)
|
|
y = make([]complex128, len(YR))
|
|
for i, v := range YR {
|
|
y[i] = complex(v, YI[i])
|
|
}
|
|
NW = Zseri(z, FNU, KODE, NN, y[1:], TOL, ELIM, ALIM)
|
|
for i, v := range y {
|
|
YR[i] = real(v)
|
|
YI[i] = imag(v)
|
|
}
|
|
goto Forty
|
|
Twenty:
|
|
if AZ < RL {
|
|
goto Thirty
|
|
}
|
|
// ASYMPTOTIC EXPANSION FOR LARGE Z FOR THE I FUNCTION.
|
|
ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, RL, TOL, ELIM, ALIM = Zasyi(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, RL, TOL, ELIM, ALIM)
|
|
if NW < 0 {
|
|
goto Eighty
|
|
}
|
|
goto Forty
|
|
Thirty:
|
|
// MILLER ALGORITHM NORMALIZED BY THE SERIES FOR THE I FUNCTION
|
|
ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL = Zmlri(ZNR, ZNI, FNU, KODE, NN, YR, YI, NW, TOL)
|
|
if NW < 0 {
|
|
goto Eighty
|
|
}
|
|
Forty:
|
|
// ANALYTIC CONTINUATION TO THE LEFT HALF PLANE FOR THE K FUNCTION.
|
|
ZNR, ZNI, FNU, KODE, _, CYR, CYI, NW, TOL, ELIM, ALIM = Zbknu(ZNR, ZNI, FNU, KODE, 1, CYR, CYI, NW, TOL, ELIM, ALIM)
|
|
if NW != 0 {
|
|
goto Eighty
|
|
}
|
|
FMR = float64(float32(MR))
|
|
SGN = -math.Copysign(PI, FMR)
|
|
CSGNR = 0.0E0
|
|
CSGNI = SGN
|
|
if KODE == 1 {
|
|
goto Fifty
|
|
}
|
|
YY = -ZNI
|
|
//sin, cos = math.Sincos(YY)
|
|
CSGNR = -CSGNI * math.Sin(YY)
|
|
CSGNI = CSGNI * math.Cos(YY)
|
|
Fifty:
|
|
// CALCULATE CSPN=EXP(FNU*PI*I) TO MINIMIZE LOSSES OF SIGNIFICANCE
|
|
// WHEN FNU IS LARGE
|
|
INU = int(float32(FNU))
|
|
ARG = (FNU - float64(float32(INU))) * SGN
|
|
//sin, cos = math.Sincos(ARG)
|
|
CSPNR = math.Cos(ARG)
|
|
CSPNI = math.Sin(ARG)
|
|
if INU%2 == 0 {
|
|
goto Sixty
|
|
}
|
|
CSPNR = -CSPNR
|
|
CSPNI = -CSPNI
|
|
Sixty:
|
|
C1R = CYR[1]
|
|
C1I = CYI[1]
|
|
C2R = YR[1]
|
|
C2I = YI[1]
|
|
if KODE == 1 {
|
|
goto Seventy
|
|
}
|
|
IUF = 0
|
|
ASCLE = 1.0E+3 * dmach[1] / TOL
|
|
zn = complex(ZNR, ZNI)
|
|
c1 = complex(C1R, C1I)
|
|
c2 = complex(C2R, C2I)
|
|
c1, c2, NW, IUF = Zs1s2(zn, c1, c2, ASCLE, ALIM, IUF)
|
|
C1R = real(c1)
|
|
C1I = imag(c1)
|
|
C2R = real(c2)
|
|
C2I = imag(c2)
|
|
NZ = NZ + NW
|
|
Seventy:
|
|
YR[1] = CSPNR*C1R - CSPNI*C1I + CSGNR*C2R - CSGNI*C2I
|
|
YI[1] = CSPNR*C1I + CSPNI*C1R + CSGNR*C2I + CSGNI*C2R
|
|
return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
Eighty:
|
|
NZ = -1
|
|
if NW == -2 {
|
|
NZ = -2
|
|
}
|
|
return ZR, ZI, FNU, KODE, MR, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
}
|
|
|
|
// ZASYI COMPUTES THE I BESSEL FUNCTION FOR REAL(Z)>=0.0 BY
|
|
// MEANS OF THE ASYMPTOTIC EXPANSION FOR LARGE CABS(Z) IN THE
|
|
// REGION CABS(Z)>MAX(RL,FNU*FNU/2). NZ=0 IS A NORMAL return.
|
|
// NZ<0 INDICATES AN OVERFLOW ON KODE=1.
|
|
func Zasyi(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, RL, TOL, ELIM, ALIM float64) (
|
|
ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, RLout, TOLout, ELIMout, ALIMout float64) {
|
|
var AA, AEZ, AK, AK1I, AK1R, ARG, ARM, ATOL,
|
|
AZ, BB, BK, CKI, CKR, CONEI, CONER, CS1I, CS1R, CS2I, CS2R, CZI,
|
|
CZR, DFNU, DKI, DKR, DNU2, EZI, EZR, FDN, PI, P1I,
|
|
P1R, RAZ, RTPI, RTR1, RZI, RZR, S, SGN, SQK, STI, STR, S2I,
|
|
S2R, TZI, TZR, ZEROI, ZEROR float64
|
|
|
|
var I, IB, IL, INU, J, JL, K, KODED, M, NN int
|
|
var tmp complex128
|
|
// var sin, cos float64
|
|
|
|
PI = math.Pi
|
|
RTPI = 0.159154943091895336E0
|
|
ZEROR = 0
|
|
ZEROI = 0
|
|
CONER = 1
|
|
CONEI = 0
|
|
|
|
NZ = 0
|
|
AZ = cmplx.Abs(complex(ZR, ZI))
|
|
ARM = 1.0E3 * dmach[1]
|
|
RTR1 = math.Sqrt(ARM)
|
|
IL = min(2, N)
|
|
DFNU = FNU + float64(float32(N-IL))
|
|
|
|
// OVERFLOW TEST
|
|
RAZ = 1.0E0 / AZ
|
|
STR = ZR * RAZ
|
|
STI = -ZI * RAZ
|
|
AK1R = RTPI * STR * RAZ
|
|
AK1I = RTPI * STI * RAZ
|
|
tmp = cmplx.Sqrt(complex(AK1R, AK1I))
|
|
AK1R = real(tmp)
|
|
AK1I = imag(tmp)
|
|
CZR = ZR
|
|
CZI = ZI
|
|
if KODE != 2 {
|
|
goto Ten
|
|
}
|
|
CZR = ZEROR
|
|
CZI = ZI
|
|
Ten:
|
|
if math.Abs(CZR) > ELIM {
|
|
goto OneHundred
|
|
}
|
|
DNU2 = DFNU + DFNU
|
|
KODED = 1
|
|
if (math.Abs(CZR) > ALIM) && (N > 2) {
|
|
goto Twenty
|
|
}
|
|
KODED = 0
|
|
tmp = cmplx.Exp(complex(CZR, CZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
tmp = complex(AK1R, AK1I) * complex(STR, STI)
|
|
AK1R = real(tmp)
|
|
AK1I = imag(tmp)
|
|
Twenty:
|
|
FDN = 0.0E0
|
|
if DNU2 > RTR1 {
|
|
FDN = DNU2 * DNU2
|
|
}
|
|
EZR = ZR * 8.0E0
|
|
EZI = ZI * 8.0E0
|
|
|
|
// WHEN Z IS IMAGINARY, THE ERROR TEST MUST BE MADE RELATIVE TO THE
|
|
// FIRST RECIPROCAL POWER SINCE THIS IS THE LEADING TERM OF THE
|
|
// EXPANSION FOR THE IMAGINARY PART.
|
|
AEZ = 8.0E0 * AZ
|
|
S = TOL / AEZ
|
|
JL = int(float32(RL+RL)) + 2
|
|
P1R = ZEROR
|
|
P1I = ZEROI
|
|
if ZI == 0.0E0 {
|
|
goto Thirty
|
|
}
|
|
|
|
// CALCULATE EXP(PI*(0.5+FNU+N-IL)*I) TO MINIMIZE LOSSES OF
|
|
// SIGNIFICANCE WHEN FNU OR N IS LARGE
|
|
INU = int(float32(FNU))
|
|
ARG = (FNU - float64(float32(INU))) * PI
|
|
INU = INU + N - IL
|
|
//sin, cos = math.Sincos(ARG)
|
|
AK = -math.Sin(ARG)
|
|
BK = math.Cos(ARG)
|
|
if ZI < 0.0E0 {
|
|
BK = -BK
|
|
}
|
|
P1R = AK
|
|
P1I = BK
|
|
if INU%2 == 0 {
|
|
goto Thirty
|
|
}
|
|
P1R = -P1R
|
|
P1I = -P1I
|
|
Thirty:
|
|
for K = 1; K <= IL; K++ {
|
|
SQK = FDN - 1.0E0
|
|
ATOL = S * math.Abs(SQK)
|
|
SGN = 1.0E0
|
|
CS1R = CONER
|
|
CS1I = CONEI
|
|
CS2R = CONER
|
|
CS2I = CONEI
|
|
CKR = CONER
|
|
CKI = CONEI
|
|
AK = 0.0E0
|
|
AA = 1.0E0
|
|
BB = AEZ
|
|
DKR = EZR
|
|
DKI = EZI
|
|
// TODO(btracey): This loop is executed tens of thousands of times. Why?
|
|
// is that really necessary?
|
|
for J = 1; J <= JL; J++ {
|
|
tmp = complex(CKR, CKI) / complex(DKR, DKI)
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
CKR = STR * SQK
|
|
CKI = STI * SQK
|
|
CS2R = CS2R + CKR
|
|
CS2I = CS2I + CKI
|
|
SGN = -SGN
|
|
CS1R = CS1R + CKR*SGN
|
|
CS1I = CS1I + CKI*SGN
|
|
DKR = DKR + EZR
|
|
DKI = DKI + EZI
|
|
AA = AA * math.Abs(SQK) / BB
|
|
BB = BB + AEZ
|
|
AK = AK + 8.0E0
|
|
SQK = SQK - AK
|
|
if AA <= ATOL {
|
|
goto Fifty
|
|
}
|
|
}
|
|
goto OneTen
|
|
Fifty:
|
|
S2R = CS1R
|
|
S2I = CS1I
|
|
if ZR+ZR >= ELIM {
|
|
goto Sixty
|
|
}
|
|
TZR = ZR + ZR
|
|
TZI = ZI + ZI
|
|
tmp = cmplx.Exp(complex(-TZR, -TZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
tmp = complex(STR, STI) * complex(P1R, P1I)
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
tmp = complex(STR, STI) * complex(CS2R, CS2I)
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
S2R = S2R + STR
|
|
S2I = S2I + STI
|
|
Sixty:
|
|
FDN = FDN + 8.0E0*DFNU + 4.0E0
|
|
P1R = -P1R
|
|
P1I = -P1I
|
|
M = N - IL + K
|
|
YR[M] = S2R*AK1R - S2I*AK1I
|
|
YI[M] = S2R*AK1I + S2I*AK1R
|
|
}
|
|
if N <= 2 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
}
|
|
NN = N
|
|
K = NN - 2
|
|
AK = float64(float32(K))
|
|
STR = ZR * RAZ
|
|
STI = -ZI * RAZ
|
|
RZR = (STR + STR) * RAZ
|
|
RZI = (STI + STI) * RAZ
|
|
IB = 3
|
|
for I = IB; I <= NN; I++ {
|
|
YR[K] = (AK+FNU)*(RZR*YR[K+1]-RZI*YI[K+1]) + YR[K+2]
|
|
YI[K] = (AK+FNU)*(RZR*YI[K+1]+RZI*YR[K+1]) + YI[K+2]
|
|
AK = AK - 1.0E0
|
|
K = K - 1
|
|
}
|
|
if KODED == 0 {
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
}
|
|
tmp = cmplx.Exp(complex(CZR, CZI))
|
|
CKR = real(tmp)
|
|
CKI = imag(tmp)
|
|
for I = 1; I <= NN; I++ {
|
|
STR = YR[I]*CKR - YI[I]*CKI
|
|
YI[I] = YR[I]*CKI + YI[I]*CKR
|
|
YR[I] = STR
|
|
}
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
OneHundred:
|
|
NZ = -1
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
OneTen:
|
|
NZ = -2
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, RL, TOL, ELIM, ALIM
|
|
}
|
|
|
|
// ZMLRI COMPUTES THE I BESSEL FUNCTION FOR RE(Z)>=0.0 BY THE
|
|
// MILLER ALGORITHM NORMALIZED BY A NEUMANN SERIES.
|
|
func Zmlri(ZR, ZI, FNU float64, KODE, N int, YR, YI []float64, NZ int, TOL float64) (
|
|
ZRout, ZIout, FNUout float64, KODEout, Nout int, YRout, YIout []float64, NZout int, TOLout float64) {
|
|
var ACK, AK, AP, AT, AZ, BK, CKI, CKR, CNORMI,
|
|
CNORMR, CONEI, CONER, FKAP, FKK, FLAM, FNF, PTI, PTR, P1I,
|
|
P1R, P2I, P2R, RAZ, RHO, RHO2, RZI, RZR, SCLE, STI, STR, SUMI,
|
|
SUMR, TFNF, TST, ZEROI, ZEROR float64
|
|
var I, IAZ, IDUM, IFNU, INU, ITIME, K, KK, KM, M int
|
|
var tmp complex128
|
|
ZEROR = 0
|
|
ZEROI = 0
|
|
CONER = 1
|
|
CONEI = 0
|
|
|
|
SCLE = dmach[1] / TOL
|
|
NZ = 0
|
|
AZ = cmplx.Abs(complex(ZR, ZI))
|
|
IAZ = int(float32(AZ))
|
|
IFNU = int(float32(FNU))
|
|
INU = IFNU + N - 1
|
|
AT = float64(float32(IAZ)) + 1.0E0
|
|
RAZ = 1.0E0 / AZ
|
|
STR = ZR * RAZ
|
|
STI = -ZI * RAZ
|
|
CKR = STR * AT * RAZ
|
|
CKI = STI * AT * RAZ
|
|
RZR = (STR + STR) * RAZ
|
|
RZI = (STI + STI) * RAZ
|
|
P1R = ZEROR
|
|
P1I = ZEROI
|
|
P2R = CONER
|
|
P2I = CONEI
|
|
ACK = (AT + 1.0E0) * RAZ
|
|
RHO = ACK + math.Sqrt(ACK*ACK-1.0E0)
|
|
RHO2 = RHO * RHO
|
|
TST = (RHO2 + RHO2) / ((RHO2 - 1.0E0) * (RHO - 1.0E0))
|
|
TST = TST / TOL
|
|
|
|
// COMPUTE RELATIVE TRUNCATION ERROR INDEX FOR SERIES.
|
|
//fmt.Println("before loop", P2R, P2I, CKR, CKI, RZR, RZI, TST, AK)
|
|
AK = AT
|
|
for I = 1; I <= 80; I++ {
|
|
PTR = P2R
|
|
PTI = P2I
|
|
P2R = P1R - (CKR*PTR - CKI*PTI)
|
|
P2I = P1I - (CKI*PTR + CKR*PTI)
|
|
P1R = PTR
|
|
P1I = PTI
|
|
CKR = CKR + RZR
|
|
CKI = CKI + RZI
|
|
AP = cmplx.Abs(complex(P2R, P2I))
|
|
if AP > TST*AK*AK {
|
|
goto Twenty
|
|
}
|
|
AK = AK + 1.0E0
|
|
}
|
|
goto OneTen
|
|
Twenty:
|
|
I = I + 1
|
|
K = 0
|
|
if INU < IAZ {
|
|
goto Forty
|
|
}
|
|
// COMPUTE RELATIVE TRUNCATION ERROR FOR RATIOS.
|
|
P1R = ZEROR
|
|
P1I = ZEROI
|
|
P2R = CONER
|
|
P2I = CONEI
|
|
AT = float64(float32(INU)) + 1.0E0
|
|
STR = ZR * RAZ
|
|
STI = -ZI * RAZ
|
|
CKR = STR * AT * RAZ
|
|
CKI = STI * AT * RAZ
|
|
ACK = AT * RAZ
|
|
TST = math.Sqrt(ACK / TOL)
|
|
ITIME = 1
|
|
for K = 1; K <= 80; K++ {
|
|
PTR = P2R
|
|
PTI = P2I
|
|
P2R = P1R - (CKR*PTR - CKI*PTI)
|
|
P2I = P1I - (CKR*PTI + CKI*PTR)
|
|
P1R = PTR
|
|
P1I = PTI
|
|
CKR = CKR + RZR
|
|
CKI = CKI + RZI
|
|
AP = cmplx.Abs(complex(P2R, P2I))
|
|
if AP < TST {
|
|
continue
|
|
}
|
|
if ITIME == 2 {
|
|
goto Forty
|
|
}
|
|
ACK = cmplx.Abs(complex(CKR, CKI))
|
|
FLAM = ACK + math.Sqrt(ACK*ACK-1.0E0)
|
|
FKAP = AP / cmplx.Abs(complex(P1R, P1I))
|
|
RHO = math.Min(FLAM, FKAP)
|
|
TST = TST * math.Sqrt(RHO/(RHO*RHO-1.0E0))
|
|
ITIME = 2
|
|
}
|
|
goto OneTen
|
|
Forty:
|
|
// BACKWARD RECURRENCE AND SUM NORMALIZING RELATION.
|
|
K = K + 1
|
|
KK = max(I+IAZ, K+INU)
|
|
FKK = float64(float32(KK))
|
|
P1R = ZEROR
|
|
P1I = ZEROI
|
|
|
|
// SCALE P2 AND SUM BY SCLE.
|
|
P2R = SCLE
|
|
P2I = ZEROI
|
|
FNF = FNU - float64(float32(IFNU))
|
|
TFNF = FNF + FNF
|
|
BK = dgamln(FKK+TFNF+1.0E0, IDUM) - dgamln(FKK+1.0E0, IDUM) - dgamln(TFNF+1.0E0, IDUM)
|
|
BK = math.Exp(BK)
|
|
SUMR = ZEROR
|
|
SUMI = ZEROI
|
|
KM = KK - INU
|
|
for I = 1; I <= KM; I++ {
|
|
PTR = P2R
|
|
PTI = P2I
|
|
P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI)
|
|
P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI)
|
|
P1R = PTR
|
|
P1I = PTI
|
|
AK = 1.0E0 - TFNF/(FKK+TFNF)
|
|
ACK = BK * AK
|
|
SUMR = SUMR + (ACK+BK)*P1R
|
|
SUMI = SUMI + (ACK+BK)*P1I
|
|
BK = ACK
|
|
FKK = FKK - 1.0E0
|
|
}
|
|
YR[N] = P2R
|
|
YI[N] = P2I
|
|
if N == 1 {
|
|
goto Seventy
|
|
}
|
|
for I = 2; I <= N; I++ {
|
|
PTR = P2R
|
|
PTI = P2I
|
|
P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI)
|
|
P2I = P1I + (FKK+FNF)*(RZI*PTR+RZR*PTI)
|
|
P1R = PTR
|
|
P1I = PTI
|
|
AK = 1.0E0 - TFNF/(FKK+TFNF)
|
|
ACK = BK * AK
|
|
SUMR = SUMR + (ACK+BK)*P1R
|
|
SUMI = SUMI + (ACK+BK)*P1I
|
|
BK = ACK
|
|
FKK = FKK - 1.0E0
|
|
M = N - I + 1
|
|
YR[M] = P2R
|
|
YI[M] = P2I
|
|
}
|
|
Seventy:
|
|
if IFNU <= 0 {
|
|
goto Ninety
|
|
}
|
|
for I = 1; I <= IFNU; I++ {
|
|
PTR = P2R
|
|
PTI = P2I
|
|
P2R = P1R + (FKK+FNF)*(RZR*PTR-RZI*PTI)
|
|
P2I = P1I + (FKK+FNF)*(RZR*PTI+RZI*PTR)
|
|
P1R = PTR
|
|
P1I = PTI
|
|
AK = 1.0E0 - TFNF/(FKK+TFNF)
|
|
ACK = BK * AK
|
|
SUMR = SUMR + (ACK+BK)*P1R
|
|
SUMI = SUMI + (ACK+BK)*P1I
|
|
BK = ACK
|
|
FKK = FKK - 1.0E0
|
|
}
|
|
Ninety:
|
|
PTR = ZR
|
|
PTI = ZI
|
|
if KODE == 2 {
|
|
PTR = ZEROR
|
|
}
|
|
tmp = cmplx.Log(complex(RZR, RZI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
P1R = -FNF*STR + PTR
|
|
P1I = -FNF*STI + PTI
|
|
AP = dgamln(1.0E0+FNF, IDUM)
|
|
PTR = P1R - AP
|
|
PTI = P1I
|
|
|
|
// THE DIVISION CEXP(PT)/(SUM+P2) IS ALTERED TO AVOID OVERFLOW
|
|
// IN THE DENOMINATOR BY SQUARING LARGE QUANTITIES.
|
|
P2R = P2R + SUMR
|
|
P2I = P2I + SUMI
|
|
AP = cmplx.Abs(complex(P2R, P2I))
|
|
P1R = 1.0E0 / AP
|
|
tmp = cmplx.Exp(complex(PTR, PTI))
|
|
STR = real(tmp)
|
|
STI = imag(tmp)
|
|
CKR = STR * P1R
|
|
CKI = STI * P1R
|
|
PTR = P2R * P1R
|
|
PTI = -P2I * P1R
|
|
tmp = complex(CKR, CKI) * complex(PTR, PTI)
|
|
CNORMR = real(tmp)
|
|
CNORMI = imag(tmp)
|
|
for I = 1; I <= N; I++ {
|
|
STR = YR[I]*CNORMR - YI[I]*CNORMI
|
|
YI[I] = YR[I]*CNORMI + YI[I]*CNORMR
|
|
YR[I] = STR
|
|
}
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL
|
|
OneTen:
|
|
NZ = -2
|
|
return ZR, ZI, FNU, KODE, N, YR, YI, NZ, TOL
|
|
}
|
|
|
|
// Zseri computes the I bessel function for real(z) >= 0 by means of the power
|
|
// series for large |z| in the region |z| <= 2*sqrt(fnu+1).
|
|
//
|
|
// nz = 0 is a normal return. nz > 0 means that the last nz components were set
|
|
// to zero due to underflow. nz < 0 means that underflow occurred, but the
|
|
// condition |z| <= 2*sqrt(fnu+1) was violated and the computation must be
|
|
// completed in another routine with n -= abs(nz).
|
|
func Zseri(z complex128, fnu float64, kode, n int, y []complex128, tol, elim, alim float64) (nz int) {
|
|
// TODO(btracey): The original fortran line is "ARM = 1.0D+3*D1MACH(1)". Evidently, in Fortran
|
|
// this is interpreted as one to the power of +3*D1MACH(1). While it is possible
|
|
// this was intentional, it seems unlikely.
|
|
arm := 1000 * dmach[1]
|
|
az := cmplx.Abs(z)
|
|
if az < arm {
|
|
for i := 0; i < n; i++ {
|
|
y[i] = 0
|
|
}
|
|
if fnu == 0 {
|
|
y[0] = 1
|
|
n--
|
|
}
|
|
if az == 0 {
|
|
return 0
|
|
}
|
|
return n
|
|
}
|
|
hz := 0.5 * z
|
|
var cz complex128
|
|
var acz float64
|
|
if az > math.Sqrt(arm) {
|
|
cz = hz * hz
|
|
acz = cmplx.Abs(cz)
|
|
}
|
|
NN := n
|
|
ck := cmplx.Log(hz)
|
|
var ak1 complex128
|
|
for {
|
|
dfnu := fnu + float64(NN-1)
|
|
// Underflow test.
|
|
ak1 = ck * complex(dfnu, 0)
|
|
ak := dgamln(dfnu+1, 0)
|
|
ak1 -= complex(ak, 0)
|
|
if kode == 2 {
|
|
ak1 -= complex(real(z), 0)
|
|
}
|
|
if real(ak1) > -elim {
|
|
break
|
|
}
|
|
nz++
|
|
y[NN-1] = 0
|
|
if acz > dfnu {
|
|
// Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation
|
|
// in cbinu with n = n - abs(nz).
|
|
nz *= -1
|
|
return nz
|
|
}
|
|
NN--
|
|
if NN == 0 {
|
|
return nz
|
|
}
|
|
}
|
|
crscr := 1.0
|
|
var flag int
|
|
var scale float64
|
|
aa := real(ak1)
|
|
if aa <= -alim {
|
|
flag = 1
|
|
crscr = tol
|
|
scale = arm / tol
|
|
aa -= math.Log(tol)
|
|
}
|
|
var w [2]complex128
|
|
for {
|
|
coef := cmplx.Exp(complex(aa, imag(ak1)))
|
|
atol := tol * acz / (fnu + float64(NN))
|
|
for i := 0; i < min(2, NN); i++ {
|
|
FNUP := fnu + float64(NN-i)
|
|
s1 := 1 + 0i
|
|
if acz >= tol*FNUP {
|
|
ak2 := 1 + 0i
|
|
ak := FNUP + 2
|
|
S := FNUP
|
|
scl := 2.0
|
|
first := true
|
|
for first || scl > atol {
|
|
ak2 = ak2 * cz * complex(1/S, 0)
|
|
scl *= acz / S
|
|
s1 += ak2
|
|
S += ak
|
|
ak += 2
|
|
first = false
|
|
}
|
|
}
|
|
s2 := s1 * coef
|
|
w[i] = s2
|
|
if flag == 1 {
|
|
if Zuchk(s2, scale, tol) != 0 {
|
|
var full bool
|
|
var dfnu float64
|
|
// This code is similar to the code that exists above. The
|
|
// code copying is here because the original Fortran used
|
|
// a goto to solve the loop-and-a-half problem. Removing the
|
|
// goto makes the behavior of the function and variable scoping
|
|
// much clearer, but requires copying this code due to Go's
|
|
// goto rules.
|
|
for {
|
|
if full {
|
|
dfnu = fnu + float64(NN-1)
|
|
// Underflow test.
|
|
ak1 = ck * complex(dfnu, 0)
|
|
ak1 -= complex(dgamln(dfnu+1, 0), 0)
|
|
if kode == 2 {
|
|
ak1 -= complex(real(z), 0)
|
|
}
|
|
if real(ak1) > -elim {
|
|
break
|
|
}
|
|
} else {
|
|
full = true
|
|
}
|
|
nz++
|
|
y[NN-1] = 0
|
|
if acz > dfnu {
|
|
// Return with nz < 0 if abs(Z*Z/4)>fnu+u-nz-1 complete the calculation
|
|
// in cbinu with n = n - abs(nz).
|
|
nz *= -1
|
|
return nz
|
|
}
|
|
NN--
|
|
if NN == 0 {
|
|
return nz
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
y[NN-i-1] = s2 * complex(crscr, 0)
|
|
coef /= hz
|
|
coef *= complex(FNUP-1, 0)
|
|
}
|
|
break
|
|
}
|
|
if NN <= 2 {
|
|
return nz
|
|
}
|
|
rz := complex(2*real(z)/(az*az), -2*imag(z)/(az*az))
|
|
if flag == 0 {
|
|
for i := NN - 3; i >= 0; i-- {
|
|
y[i] = complex(float64(i+1)+fnu, 0)*rz*y[i+1] + y[i+2]
|
|
}
|
|
return nz
|
|
}
|
|
|
|
// exp(-alim)=exp(-elim)/tol=approximately one digit of precision above the
|
|
// underflow limit, which equals scale = dmach[1)*SS*1e3.
|
|
s1 := w[0]
|
|
s2 := w[1]
|
|
for K := NN - 3; K >= 0; K-- {
|
|
s1, s2 = s2, s1+complex(float64(K+1)+fnu, 0)*(rz*s2)
|
|
ck := s2 * complex(crscr, 0)
|
|
y[K] = ck
|
|
if cmplx.Abs(ck) > scale {
|
|
for ; K >= 0; K-- {
|
|
y[K] = complex(float64(K+1)+fnu, 0)*rz*y[K+1] + y[K+2]
|
|
}
|
|
return nz
|
|
}
|
|
}
|
|
return nz
|
|
}
|
|
|
|
// Zs1s2 tests for a possible underflow resulting from the addition of the I and
|
|
// K functions in the analytic continuation formula where s1 == K function and
|
|
// s2 == I function.
|
|
//
|
|
// When kode == 1, the I and K functions are different orders of magnitude.
|
|
//
|
|
// When kode == 2, they may both be of the same order of magnitude, but the maximum
|
|
// must be at least one precision above the underflow limit.
|
|
func Zs1s2(zr, s1, s2 complex128, scale, lim float64, iuf int) (s1o, s2o complex128, nz, iufo int) {
|
|
if s1 == 0 || math.Log(cmplx.Abs(s1))-2*real(zr) < -lim {
|
|
if cmplx.Abs(s2) > scale {
|
|
return 0, s2, 0, iuf
|
|
}
|
|
return 0, 0, 1, 0
|
|
}
|
|
// TODO(btracey): Written like this for numerical rounding reasons.
|
|
// Fix once we're sure other changes are correct.
|
|
s1 = cmplx.Exp(cmplx.Log(s1) - zr - zr)
|
|
if math.Max(cmplx.Abs(s1), cmplx.Abs(s2)) > scale {
|
|
return s1, s2, 0, iuf + 1
|
|
}
|
|
return 0, 0, 1, 0
|
|
}
|
|
|
|
func dgamln(z float64, ierr int) float64 {
|
|
//return amoslib.DgamlnFort(z)
|
|
// Go implementation.
|
|
if z < 0 {
|
|
return 0
|
|
}
|
|
a2, _ := math.Lgamma(z)
|
|
return a2
|
|
}
|