elliptic.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 namespace ::math::special {
00014 namespace export cn sn dn
00015
00016 ::math::constants::constants pi
00017
00018 variable halfpi [expr {$pi/2.0}]
00019 variable tol
00020
00021 tol = 1.0e-10
00022 }
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 ret ::math::special::elliptic_K (type k) {
00035 variable halfpi
00036 if { $k < 0.0 || $k >= 1.0 } {
00037 error "Domain error: must be between 0 (inclusive) and 1 (not inclusive)"
00038 }
00039
00040 if { $k == 0.0 } {
00041 return $halfpi
00042 }
00043
00044 set a 1.0
00045 set b [expr {sqrt(1.0-$k*$k)}]
00046
00047 for {set i 0} {$i < 10} {incr i} {
00048 set anew [expr {($a+$b)/2.0}]
00049 set bnew [expr {sqrt($a*$b)}]
00050
00051 set a $anew
00052 set b $bnew
00053 #puts "$a $b"
00054 }
00055
00056 return [expr {$halfpi/$a}]
00057 }
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 ret ::math::special::elliptic_E (type k) {
00070 variable halfpi
00071 if { $k < 0.0 || $k >= 1.0 } {
00072 error "Domain error: must be between 0 (inclusive) and 1 (not inclusive)"
00073 }
00074
00075 if { $k == 0.0 } {
00076 return $halfpi
00077 }
00078 if { $k == 1.0 } {
00079 return 1.0
00080 }
00081
00082 set a 1.0
00083 set b [expr {sqrt(1.0-$k*$k)}]
00084 set sumc [expr {$k*$k/2.0}]
00085 set factor 0.25
00086
00087 for {set i 0} {$i < 10} {incr i} {
00088 set anew [expr {($a+$b)/2.0}]
00089 set bnew [expr {sqrt($a*$b)}]
00090 set sumc [expr {$sumc+$factor*($a-$b)*($a-$b)}]
00091 set factor [expr {$factor*2.0}]
00092
00093 set a $anew
00094 set b $bnew
00095 #puts "$a $b"
00096 }
00097
00098 set Kk [expr {$halfpi/$a}]
00099 return [expr {(1.0-$sumc)*$Kk}]
00100 }
00101
00102 namespace ::math::special {
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 ret ::math::special::Nextk ( type k ) {
00114 set ksq [expr {sqrt(1.0-$k*$k)}]
00115 return [expr {(1.0-$ksq)/(1+$ksq)}]
00116 }
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 ret ::math::special::IterateUK ( type u , type k ) {
00128 variable tol
00129 set kvalues {}
00130 set nmax 1
00131 while { $k > $tol } {
00132 set k [Nextk $k]
00133 set kvalues [concat $k $kvalues]
00134 set u [expr {$u*2.0/(1.0+$k)}]
00135 incr nmax
00136 #puts "$nmax -$u - $k"
00137 }
00138 foreach k $kvalues {
00139 set u [expr {( $u + asin($k*sin($u)) )/2.0}]
00140 }
00141 return $u
00142 }
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 ret ::math::special::cn ( type u , type k ) {
00156 if { $k > 1.0 } {
00157 return -code error "Parameter out of range - must be <= 1.0"
00158 }
00159 if { $k == 1.0 } {
00160 return [expr {1.0/cosh($u)}]
00161 } else {
00162 set u [IterateUK $u $k]
00163 return [expr {cos($u)}]
00164 }
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178 ret ::math::special::sn ( type u , type k ) {
00179 if { $k > 1.0 } {
00180 return -code error "Parameter out of range - must be <= 1.0"
00181 }
00182 if { $k == 1.0 } {
00183 return [expr {tanh($u)}]
00184 } else {
00185 set u [IterateUK $u $k]
00186 return [expr {sin($u)}]
00187 }
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 ret ::math::special::sn ( type u , type k ) {
00202 if { $k > 1.0 } {
00203 return -code error "Parameter out of range - must be <= 1.0"
00204 }
00205 if { $k == 1.0 } {
00206 return [expr {1.0/cosh($u)}]
00207 } else {
00208 set u [IterateUK $u $k]
00209 return [expr {sqrt(1.0-$k*$k*sin($u)}]
00210 }
00211 }
00212
00213
00214
00215
00216
00217 if { 0 } {
00218 puts "Special cases:"
00219 puts "cos(1): [::math::special::cn 1.0 0.0] -- [expr {cos(1.0)}]"
00220 puts "1/cosh(1): [::math::special::cn 1.0 0.999] -- [expr {1.0/cosh(1.0)}]"
00221 }
00222
00223
00224
00225 if { 0 } {
00226 tcl = _precision 17
00227
00228
00229
00230 foreach k2 {0.0 0.1 0.2 0.4 0.6 0.8 0.9} {
00231 k = [expr {sqrt($k2)}]
00232 puts "$k2: [::math::special::elliptic_K $k] \
00233 [::math::special::elliptic_E $k]"
00234 }
00235 }
00236
00237