|
| 1 | +using Base.Math.@horner |
| 2 | + |
| 3 | +# Compute the sine integral: ∫_0^x sin(t)/t dt, |
| 4 | +# and the cosine integral: γ + log x + ∫_0^x (cos(t)-1)/t dt, |
| 5 | +# using the rational approximants tabulated in: |
| 6 | +# A.J. MacLeod, "Rational approximations, software and test methods for |
| 7 | +# sine and cosine integrals," Numer. Algor. 12, pp. 259--272 (1996). |
| 8 | +# http://dx.doi.org/10.1007/BF02142806 |
| 9 | +# https://link.springer.com/article/10.1007/BF02142806 |
| 10 | +# |
| 11 | +# Note: the second zero of Ci(x) has a typo that is fixed: |
| 12 | +# |
| 13 | +# r1 = 3.38418 04228 51186 42639 78511 46402 in the article, but is in fact: |
| 14 | +# |
| 15 | +# r1 = 3.38418 04225 51186 42639 78511 46402. |
| 16 | +# |
| 17 | + |
| 18 | +function sinint(x::Float64) |
| 19 | + t = x*x |
| 20 | + if t ≤ 36.0 |
| 21 | + return x * @horner(t, 1.00000000000000000000E0, |
| 22 | + -0.44663998931312457298E-1, |
| 23 | + 0.11209146443112369449E-2, |
| 24 | + -0.13276124407928422367E-4, |
| 25 | + 0.85118014179823463879E-7, |
| 26 | + -0.29989314303147656479E-9, |
| 27 | + 0.55401971660186204711E-12, |
| 28 | + -0.42406353433133212926E-15) / |
| 29 | + @horner(t, 1.00000000000000000000E0, |
| 30 | + 0.10891556624243098264E-1, |
| 31 | + 0.59334456769186835896E-4, |
| 32 | + 0.21231112954641805908E-6, |
| 33 | + 0.54747121846510390750E-9, |
| 34 | + 0.10378561511331814674E-11, |
| 35 | + 0.13754880327250272679E-14, |
| 36 | + 0.10223981202236205703E-17) |
| 37 | + elseif t ≤ 144.0 |
| 38 | + invt = inv(t) |
| 39 | + return copysign(π/2, x) - cos(x) * |
| 40 | + @horner(invt, 0.99999999962173909991E0, |
| 41 | + 0.36451060338631902917E3, |
| 42 | + 0.44218548041288440874E5, |
| 43 | + 0.22467569405961151887E7, |
| 44 | + 0.49315316723035561922E8, |
| 45 | + 0.43186795279670283193E9, |
| 46 | + 0.11847992519956804350E10, |
| 47 | + 0.45573267593795103181E9) / |
| 48 | + (x * @horner(invt, 1.00000000000000000000E0, |
| 49 | + 0.36651060273229347594E3, |
| 50 | + 0.44927569814970692777E5, |
| 51 | + 0.23285354882204041700E7, |
| 52 | + 0.53117852017228262911E8, |
| 53 | + 0.50335310667241870372E9, |
| 54 | + 0.16575285015623175410E10, |
| 55 | + 0.11746532837038341076E10)) - |
| 56 | + sin(x)*invt * @horner(invt, 0.99999999920484901956E0, |
| 57 | + 0.51385504875307321394E3, |
| 58 | + 0.92293483452013810811E5, |
| 59 | + 0.74071341863359841727E7, |
| 60 | + 0.28142356162841356551E9, |
| 61 | + 0.49280890357734623984E10, |
| 62 | + 0.35524762685554302472E11, |
| 63 | + 0.79194271662085049376E11, |
| 64 | + 0.17942522624413898907E11) / |
| 65 | + @horner(invt, 1.00000000000000000000E0, |
| 66 | + 0.51985504708814870209E3, |
| 67 | + 0.95292615508125947321E5, |
| 68 | + 0.79215459679762667578E7, |
| 69 | + 0.31977567790733781460E9, |
| 70 | + 0.62273134702439012114E10, |
| 71 | + 0.54570971054996441467E11, |
| 72 | + 0.18241750166645704670E12, |
| 73 | + 0.15407148148861454434E12) |
| 74 | + elseif t < Inf |
| 75 | + invt = inv(t) |
| 76 | + return copysign(π/2, x) - cos(x) / x * (1.0 - |
| 77 | + @horner(invt, 0.19999999999999978257E1, |
| 78 | + 0.22206119380434958727E4, |
| 79 | + 0.84749007623988236808E6, |
| 80 | + 0.13959267954823943232E9, |
| 81 | + 0.10197205463267975592E11, |
| 82 | + 0.30229865264524075951E12, |
| 83 | + 0.27504053804288471142E13, |
| 84 | + 0.21818989704686874983E13) / |
| 85 | + @horner(invt, 1.00000000000000000000E0, |
| 86 | + 0.11223059690217167788E4, |
| 87 | + 0.43685270974851313242E6, |
| 88 | + 0.74654702140658116258E8, |
| 89 | + 0.58580034751805687471E10, |
| 90 | + 0.20157980379272098841E12, |
| 91 | + 0.26229141857684496445E13, |
| 92 | + 0.87852907334918467516E13)*invt) - |
| 93 | + sin(x) * invt * (1.0 - @horner(invt, 0.59999999999999993089E1, |
| 94 | + 0.96527746044997139158E4, |
| 95 | + 0.56077626996568834185E7, |
| 96 | + 0.15022667718927317198E10, |
| 97 | + 0.19644271064733088465E12, |
| 98 | + 0.12191368281163225043E14, |
| 99 | + 0.31924389898645609533E15, |
| 100 | + 0.25876053010027485934E16, |
| 101 | + 0.12754978896268878403E16) / |
| 102 | + @horner(invt, 1.00000000000000000000E0, |
| 103 | + 0.16287957674166143196E4, |
| 104 | + 0.96636303195787870963E6, |
| 105 | + 0.26839734750950667021E9, |
| 106 | + 0.37388510548029219241E11, |
| 107 | + 0.26028585666152144496E13, |
| 108 | + 0.85134283716950697226E14, |
| 109 | + 0.11304079361627952930E16, |
| 110 | + 0.42519841479489798424E16)*invt) |
| 111 | + elseif isnan(x) |
| 112 | + return NaN |
| 113 | + else |
| 114 | + return copysign(π/2, x) |
| 115 | + end |
| 116 | +end |
| 117 | + |
| 118 | +function cosint(x::Float64) |
| 119 | + t, r0, r1 = x*x, 0.616505485620716233797110404100, 3.384180422551186426397851146402 |
| 120 | + r01, r02 = 0.6162109375, 0.29454812071623379711E-3 |
| 121 | + r11, r12 = 3.3837890625, 0.39136005118642639785E-3 |
| 122 | + if x < 0.0 |
| 123 | + return throw(DomainError()) |
| 124 | + elseif x ≤ 3.0 |
| 125 | + return log(x/r0) + ((x - r01) - r02) * (x + r0) * |
| 126 | + @horner(t, -0.24607411378767540707E0, |
| 127 | + 0.72113492241301534559E-2, |
| 128 | + -0.11867127836204767056E-3, |
| 129 | + 0.90542655466969866243E-6, |
| 130 | + -0.34322242412444409037E-8, |
| 131 | + 0.51950683460656886834E-11) / |
| 132 | + @horner(t, 1.00000000000000000000E0, |
| 133 | + 0.12670095552700637845E-1, |
| 134 | + 0.78168450570724148921E-4, |
| 135 | + 0.29959200177005821677E-6, |
| 136 | + 0.73191677761328838216E-9, |
| 137 | + 0.94351174530907529061E-12) |
| 138 | + elseif x ≤ 6.0 |
| 139 | + return log(x/r1) + ((x - r11) - r12) * (x + r1) * |
| 140 | + @horner(t, -0.15684781827145408780E0, |
| 141 | + 0.66253165609605468916E-2, |
| 142 | + -0.12822297297864512864E-3, |
| 143 | + 0.12360964097729408891E-5, |
| 144 | + -0.66450975112876224532E-8, |
| 145 | + 0.20326936466803159446E-10, |
| 146 | + -0.33590883135343844613E-13, |
| 147 | + 0.23686934961435015119E-16) / |
| 148 | + @horner(t, 1.00000000000000000000E0, |
| 149 | + 0.96166044388828741188E-2, |
| 150 | + 0.45257514591257035006E-4, |
| 151 | + 0.13544922659627723233E-6, |
| 152 | + 0.27715365686570002081E-9, |
| 153 | + 0.37718676301688932926E-12, |
| 154 | + 0.27706844497155995398E-15) |
| 155 | + elseif x ≤ 12.0 |
| 156 | + invt = inv(t) |
| 157 | + return sin(x) * @horner(invt, 0.99999999962173909991E0, |
| 158 | + 0.36451060338631902917E3, |
| 159 | + 0.44218548041288440874E5, |
| 160 | + 0.22467569405961151887E7, |
| 161 | + 0.49315316723035561922E8, |
| 162 | + 0.43186795279670283193E9, |
| 163 | + 0.11847992519956804350E10, |
| 164 | + 0.45573267593795103181E9) / |
| 165 | + (x * @horner(invt, 1.00000000000000000000E0, |
| 166 | + 0.36651060273229347594E3, |
| 167 | + 0.44927569814970692777E5, |
| 168 | + 0.23285354882204041700E7, |
| 169 | + 0.53117852017228262911E8, |
| 170 | + 0.50335310667241870372E9, |
| 171 | + 0.16575285015623175410E10, |
| 172 | + 0.11746532837038341076E10)) - |
| 173 | + cos(x) * invt * @horner(invt, 0.99999999920484901956E0, |
| 174 | + 0.51385504875307321394E3, |
| 175 | + 0.92293483452013810811E5, |
| 176 | + 0.74071341863359841727E7, |
| 177 | + 0.28142356162841356551E9, |
| 178 | + 0.49280890357734623984E10, |
| 179 | + 0.35524762685554302472E11, |
| 180 | + 0.79194271662085049376E11, |
| 181 | + 0.17942522624413898907E11) / |
| 182 | + @horner(invt, 1.00000000000000000000E0, |
| 183 | + 0.51985504708814870209E3, |
| 184 | + 0.95292615508125947321E5, |
| 185 | + 0.79215459679762667578E7, |
| 186 | + 0.31977567790733781460E9, |
| 187 | + 0.62273134702439012114E10, |
| 188 | + 0.54570971054996441467E11, |
| 189 | + 0.18241750166645704670E12, |
| 190 | + 0.15407148148861454434E12) |
| 191 | + elseif x < Inf |
| 192 | + invt = inv(t) |
| 193 | + return sin(x)/x * (1.0 - @horner(invt, 0.19999999999999978257E1, |
| 194 | + 0.22206119380434958727E4, |
| 195 | + 0.84749007623988236808E6, |
| 196 | + 0.13959267954823943232E9, |
| 197 | + 0.10197205463267975592E11, |
| 198 | + 0.30229865264524075951E12, |
| 199 | + 0.27504053804288471142E13, |
| 200 | + 0.21818989704686874983E13) / |
| 201 | + @horner(invt, 1.00000000000000000000E0, |
| 202 | + 0.11223059690217167788E4, |
| 203 | + 0.43685270974851313242E6, |
| 204 | + 0.74654702140658116258E8, |
| 205 | + 0.58580034751805687471E10, |
| 206 | + 0.20157980379272098841E12, |
| 207 | + 0.26229141857684496445E13, |
| 208 | + 0.87852907334918467516E13)*invt) - |
| 209 | + cos(x)*invt * (1.0 - @horner(invt, 0.59999999999999993089E1, |
| 210 | + 0.96527746044997139158E4, |
| 211 | + 0.56077626996568834185E7, |
| 212 | + 0.15022667718927317198E10, |
| 213 | + 0.19644271064733088465E12, |
| 214 | + 0.12191368281163225043E14, |
| 215 | + 0.31924389898645609533E15, |
| 216 | + 0.25876053010027485934E16, |
| 217 | + 0.12754978896268878403E16) / |
| 218 | + @horner(invt, 1.00000000000000000000E0, |
| 219 | + 0.16287957674166143196E4, |
| 220 | + 0.96636303195787870963E6, |
| 221 | + 0.26839734750950667021E9, |
| 222 | + 0.37388510548029219241E11, |
| 223 | + 0.26028585666152144496E13, |
| 224 | + 0.85134283716950697226E14, |
| 225 | + 0.11304079361627952930E16, |
| 226 | + 0.42519841479489798424E16)*invt) |
| 227 | + elseif isnan(x) |
| 228 | + return NaN |
| 229 | + else |
| 230 | + return 0.0 |
| 231 | + end |
| 232 | +end |
| 233 | + |
| 234 | +for f in (:sinint, :cosint) |
| 235 | + @eval begin |
| 236 | + ($f)(x::Float32) = Float32(($f)(Float64(x))) |
| 237 | + ($f)(x::Float16) = Float16(($f)(Float64(x))) |
| 238 | + ($f)(x::Real) = ($f)(float(x)) |
| 239 | + ($f)(x::AbstractFloat) = error("not implemented for ", typeof(x)) |
| 240 | + end |
| 241 | +end |
| 242 | + |
| 243 | + |
| 244 | +""" |
| 245 | + sinint(x) |
| 246 | +
|
| 247 | +Compute the sine integral function of `x`, defined by ``\\operatorname{Si}(x) := \\int_0^x\\frac{\\sin t}{t} dt`` |
| 248 | +for real `x`. |
| 249 | +""" |
| 250 | +sinint |
| 251 | + |
| 252 | +""" |
| 253 | + cosint(x) |
| 254 | +
|
| 255 | +Compute the cosine integral function of `x`, defined by ``\\operatorname{Ci}(x) := \\gamma + \\log x + \\int_0^x \\frac{\\cos t - 1}{t} dt`` |
| 256 | +for real `x > 0`, where ``\\gamma`` is the Euler-Mascheroni constant. |
| 257 | +""" |
| 258 | +cosint |
0 commit comments