exponential.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005 namespace ::math::special {
00006 variable pi 3.1415926
00007 variable gamma 0.57721566490153286
00008 variable halfpi [expr {$pi/2.0}]
00009
00010
00011
00012 variable psi {
00013 NaN
00014 -0.57721566490153286 0.42278433509846713 0.92278433509846713
00015 1.2561176684318005 1.5061176684318005 1.7061176684318005
00016 1.8727843350984672 2.0156414779556102 2.1406414779556102
00017 2.2517525890667214 2.3517525890667215 2.4426616799758123
00018 2.5259950133091458 2.6029180902322229 2.6743466616607945
00019 2.7410133283274614 2.8035133283274614 2.8623368577392259
00020 2.9178924132947812 2.9705239922421498 3.0205239922421496
00021 3.0681430398611971 3.1135975853157425 3.1570758461853079
00022 3.1987425128519744 3.2387425128519745 3.2772040513135128
00023 3.31424108835055 3.3499553740648356 3.3844381326855251
00024 3.4177714660188583 3.4500295305349873 3.4812795305349873
00025 3.5115825608380176 3.5409943255438998 3.5695657541153283
00026 3.597343531893106 3.6243705589201332 3.6506863483938172
00027 3.6763273740348428
00028 }
00029 }
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 ret ::math::special::ComputeExponFG (type x) {
00042 set x2 [expr {$x*$x}]
00043 set fx [expr {($x2*$x2+7.241163*$x2+2.463936)/
00044 ($x2*$x2+9.068580*$x2+7.157433)/$x}]
00045 set gx [expr {($x2*$x2+7.547478*$x2+1.564072)/
00046 ($x2*$x2+12.723684*$x2+15.723606)/$x2}]
00047 list $fx $gx
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 ret ::math::special::exponential_Ei ( type x , optional eps =1.0e-10 ) {
00062 variable gamma
00063
00064 if { ![string is double -strict $x] } {
00065 return -code error "expected a floating point number but found \"$x\""
00066 }
00067 if { $x < 0.0 } {
00068 return [expr { -[exponential_En 1 [expr { - $x }] $eps] }]
00069 }
00070 if { $x == 0.0 } {
00071 set message "Argument to exponential_Ei must not be zero"
00072 return -code error -errorcode [list ARITH DOMAIN $message] $message
00073 }
00074 if { $x >= -log($eps) } {
00075 # evaluate Ei(x) as an asymptotic series; the series is formally
00076 # divergent, but the leading terms give the desired value to
00077 # enough precision.
00078 set sum 0.
00079 set term 1.
00080 set k 1
00081 while { 1 } {
00082 set p $term
00083 set term [expr { $term * ( $k / $x ) }]
00084 if { $term < $eps } {
00085 break
00086 }
00087 if { $term < $p } {
00088 set sum [expr { $sum + $term }]
00089 } else {
00090 set sum [expr { $sum - $p }]
00091 break
00092 }
00093 incr k
00094 }
00095 return [expr { exp($x) * ( 1.0 + $sum ) / $x }]
00096 } elseif { $x >= 1e-18 } {
00097 # evaluate Ei(x) as a power series
00098 set sum 0.
00099 set fact 1.
00100 set pow $x
00101 set n 1
00102 while { 1 } {
00103 set fact [expr { $fact * $n }]
00104 set term [expr { $pow / $n / $fact }]
00105 set sum [expr { $sum + $term }]
00106 if { $term < $eps * $sum } break
00107 set pow [expr { $x * $pow }]
00108 incr n
00109 }
00110 return [expr { $sum + $gamma + log($x) }]
00111 } else {
00112 # Ei(x) for small x
00113 return [expr { log($x) + $gamma }]
00114 }
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 ret ::math::special::exponential_En ( type n , type x , optional epsilon =1.0e-10 ) {
00130 variable psi
00131 variable gamma
00132 if { ![string is integer -strict $n] || $n < 0 } {
00133 return -code error "expected a non-negative integer but found \"$n\""
00134 }
00135 if { ![string is double -strict $x] } {
00136 return -code error "expected a floating point number but found \"$x\""
00137 }
00138 if { $n == 0 } {
00139 if { $x == 0.0 } {
00140 return -code error "E0(0) is indeterminate"
00141 }
00142 return [expr { exp( -$x ) / $x }]
00143 }
00144 if { $n == 1 && $x < 0.0 } {
00145 return [expr {- [exponential_Ei [expr { -$x }] $eps] }]
00146 }
00147 if { $x < 0.0 } {
00148 return -code error "can't evaluate En(x) for negative x"
00149 }
00150 if { $x == 0.0 } {
00151 return [expr { 1.0 / ( $n - 1 ) }]
00152 }
00153
00154 if { $x > 1.0 } {
00155 # evaluate En(x) as a continued fraction
00156 set b [expr { $x + $n }]
00157 set c 1.e308
00158 set d [expr { 1.0 / $b }]
00159 set h $d
00160 set i 1
00161 while { 1 } {
00162 set a [expr { -$i * ( $n - 1 + $i ) }]
00163 set b [expr { $b + 2.0 }]
00164 set d [expr { 1.0 / ( $a * $d + $b ) }]
00165 set c [expr { $b + $a / $c }]
00166 set delta [expr { $c * $d }]
00167 set h [expr { $h * $delta }]
00168 if { abs( $delta - 1. ) < $epsilon } {
00169 return [expr { $h * exp(-$x) }]
00170 }
00171 incr i
00172 }
00173 } else {
00174 # evaluate En(x) as a series
00175 if { $n == 1 } {
00176 set a [expr { -log($x) - $gamma }]
00177 } else {
00178 set a [expr { 1.0 / ( $n - 1 ) }]
00179 }
00180 set f 1.0
00181 set i 1
00182 while { 1 } {
00183 set f [expr { - $f * $x / $i }]
00184 if { $i == $n - 1 } {
00185 set term [expr { $f * ([lindex $psi $n] - log($x)) }]
00186 } else {
00187 set term [expr { $f / ( $n - 1 - $i ) }]
00188 }
00189 set a [expr { $a + $term }]
00190 if { abs($term) < $epsilon * abs($a) } {
00191 return $a
00192 }
00193 incr i
00194 }
00195 }
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 ret ::math::special::exponential_E1 (type x) {
00209 if { $x <= 0.0 } {
00210 error "Domain error: x must be positive"
00211 }
00212
00213 if { $x < 1.0 } {
00214 return [expr {-log($x)+((((0.00107857*$x-0.00976004)*$x+0.05519968)*$x-0.24991055)*$x+0.99999193)*$x-0.57721566}]
00215 } else {
00216 set xexpe [expr {($x*$x+2.334733*$x+0.250621)/($x*$x+3.330657*$x+1.681534)}]
00217 return [expr {$xexpe/($x*exp($x))}]
00218 }
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228 ret ::math::special::exponential_li (type x) {
00229 if { $x < 0 } {
00230 return -code error "Argument must be positive or zero"
00231 } else {
00232 if { $x == 0.0 } {
00233 return 0.0
00234 } else {
00235 return [exponential_Ei [expr {log($x)}]]
00236 }
00237 }
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247 ret ::math::special::exponential_Shi (type x) {
00248 if { $x < 0 } {
00249 return -code error "Argument must be positive or zero"
00250 } else {
00251 if { $x == 0.0 } {
00252 return 0.0
00253 } else {
00254 proc g {x} {
00255 return [expr {sinh($x)/$x}]
00256 }
00257 return [lindex [::math::calculus::romberg g 0.0 $x] 0]
00258 }
00259 }
00260 }
00261
00262
00263
00264
00265
00266
00267
00268
00269 ret ::math::special::exponential_Chi (type x) {
00270 variable gamma
00271 if { $x < 0 } {
00272 return -code error "Argument must be positive or zero"
00273 } else {
00274 if { $x == 0.0 } {
00275 return 0.0
00276 } else {
00277 proc g {x} {
00278 return [expr {(cosh($x)-1.0)/$x}]
00279 }
00280 set integral [lindex [::math::calculus::romberg g 0.0 $x] 0]
00281 return [expr {$gamma+log($x)+$integral}]
00282 }
00283 }
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293 ret ::math::special::exponential_Si (type x) {
00294 variable halfpi
00295 if { $x < 0 } {
00296 return -code error "Argument must be positive or zero"
00297 } else {
00298 if { $x == 0.0 } {
00299 return 0.0
00300 } else {
00301 if { $x < 1.0 } {
00302 proc g {x} {
00303 return [expr {sin($x)/$x}]
00304 }
00305 return [lindex [::math::calculus::romberg g 0.0 $x] 0]
00306 } else {
00307 foreach {f g} [ComputeExponFG $x] {break}
00308 return [expr {$halfpi-$f*cos($x)-$g*sin($x)}]
00309 }
00310 }
00311 }
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321 ret ::math::special::exponential_Ci (type x) {
00322 variable gamma
00323
00324 if { $x < 0 } {
00325 return -code error "Argument must be positive or zero"
00326 } else {
00327 if { $x == 0.0 } {
00328 return 0.0
00329 } else {
00330 if { $x < 1.0 } {
00331 proc g {x} {
00332 return [expr {(cos($x)-1.0)/$x}]
00333 }
00334 set integral [lindex [::math::calculus::romberg g 0.0 $x] 0]
00335 return [expr {$gamma+log($x)+$integral}]
00336 } else {
00337 foreach {f g} [ComputeExponFG $x] {break}
00338 return [expr {$f*sin($x)-$g*cos($x)}]
00339 }
00340 }
00341 }
00342 }
00343
00344
00345
00346
00347 if { [info exists ::argv0] && ![string compare $::argv0 [info script]] } {
00348 namespace ::math::special {
00349 for { i = 0.01 } { $i < 0.505 } { i = [expr { $i + 0.01 }] } {
00350 ei = [exponential_Ei $i]
00351 e1 = [expr { - [exponential_Ei [expr { - $i }]] }]
00352 puts [format "%9.6f\t%.10g\t%.10g" $i \
00353 [expr {($ei - log($i) - 0.57721566490153286)/$i} ] \
00354 [expr {($e1 + log($i) + 0.57721566490153286) / $i }]]
00355 }
00356 puts {}
00357 for { i = 0.5 } { $i < 2.005 } { i = [expr { $i + 0.01 }] } {
00358 ei = [exponential_Ei $i]
00359 e1 = [expr { - [exponential_Ei [expr { - $i }]] }]
00360 puts [format "%9.6f\t%.10g\t%.10g" $i $ei $e1]
00361 }
00362 puts {}
00363 for {} { $i < 10.05 } { i = [expr { $i + 0.1 }] } {
00364 ei = [exponential_Ei $i]
00365 e1 = [expr { - [exponential_Ei [expr { - $i }]] }]
00366 puts [format "%9.6f\t%.10g\t%.10g" $i \
00367 [expr { $i * exp(-$i) * $ei }] \
00368 [expr { $i * exp($i) * $e1 }]]
00369
00370 }
00371 puts {}
00372 for { ooi = 0.1} { $ooi > 0.0046 } { ooi = [expr { $ooi - 0.005 }] } {
00373 i = [expr { 1.0 / $ooi }]
00374 ri = [expr { round($i) }]
00375 ei = [exponential_Ei $i]
00376 e1 = [expr { - [exponential_Ei [expr { - $i }]] }]
00377 puts [format "%9.6f\t%.10g\t%.10g\t%d" $i \
00378 [expr { $i * exp(-$i) * $ei }] \
00379 [expr { $i * exp($i) * $e1 }] \
00380 $ri]
00381 }
00382 puts {}
00383
00384
00385
00386 for { x = 0.00 } { $x < 0.505 } { x = [expr { $x + 0.01 }] } {
00387 line = [format %4.2f $x]
00388 if { $x == 0.00 } {
00389 append line { } 1.0000000
00390 } else {
00391 append line { } [format %9.7f \
00392 [expr { [exponential_En 2 $x] - $x * log($x) }]]
00393 }
00394 foreach n { 3 4 10 20 } {
00395 append line { } [format %9.7f [exponential_En $n $x]]
00396 }
00397 puts $line
00398 }
00399 puts {}
00400 for { x = 0.50 } { $x < 2.005 } { x = [expr { $x + 0.01 }] } {
00401 line = [format %4.2f $x]
00402 foreach n { 2 3 4 10 20 } {
00403 append line { } [format %9.7f [exponential_En $n $x]]
00404 }
00405 puts $line
00406 }
00407 puts {}
00408
00409 for { oox = 0.5 } { $oox > 0.1025 } { oox = [expr { $oox - 0.05 }] } {
00410 line = [format %4.2f $oox]
00411 x = [expr { 1.0 / $oox }]
00412 rx = [expr { round( $x ) }]
00413 foreach n { 2 3 4 10 20 } {
00414 en = [exponential_En $n [expr { 1.0 / $oox }]]
00415 append line { } [format %9.7f [expr { ( $x + $n ) * exp($x) * $en }]]
00416 }
00417 append line { } [format %3d $rx]
00418 puts $line
00419 }
00420 for { oox = 0.10 } { $oox > 0.005 } { oox = [expr { $oox - 0.01 }] } {
00421 line = [format %4.2f $oox]
00422 x = [expr { 1.0 / $oox }]
00423 rx = [expr { round( $x ) }]
00424 foreach n { 2 3 4 10 20 } {
00425 en = [exponential_En $n $x]
00426 append line { } [format %9.7f [expr { ( $x + $n ) * exp($x) * $en }]]
00427 }
00428 append line { } [format %3d $rx]
00429 puts $line
00430 }
00431 puts {}
00432 catch {exponential_Ei 0.0} result; puts $result
00433 }
00434 }
00435