rational_funcs.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005 package require math::polynomials
00006
00007 namespace ::math::rationalfunctions {
00008 variable count 0 ;
00009 namespace v {}
00010
00011 namespace export rationalFunction ratioCmd evalRatio \
00012 coeffsNumerator coeffsDenominator \
00013 derivRatio \
00014 addRatio subRatio multRatio \
00015 divRatio
00016
00017 namespace import ::math::polynomials::*
00018 }
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 ret ::math::rationalfunctions::rationalFunction (type num , type den) {
00031
00032 foreach coeffs [list $num $den] {
00033 foreach coeff $coeffs {
00034 if { ! [string is double -strict $coeff] } {
00035 return -code error "Coefficients must be real numbers"
00036 }
00037 }
00038 }
00039
00040 #
00041 # The leading coefficient must be non-zero
00042 #
00043 return [list RATIONAL_FUNCTION [polynomial $num] [polynomial $den]]
00044 }
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 ret ::math::rationalfunctions::ratioCmd (type num , optional den ={)} {
00056 variable count
00057
00058 if { [llength $den] == 0 } {
00059 if { [lindex $num 0] == "RATIONAL_FUNCTION" } {
00060 den = [lindex $num 2]
00061 num = [lindex $num 1]
00062 }
00063 }
00064
00065 degree1 = [expr {[llength $num]-1}]
00066 degree2 = [expr {[llength $num]-1}]
00067 body = "expr \{([join $num +\$x*(][string repeat ) $degree1])/\
00068 (double([join $den +\$x*(][string repeat ) $degree2])\}"
00069
00070 incr count
00071 name = "::math::rationalfunctions::v::RATIO$count"
00072 ret $name (type x) $body
00073 return $name
00074 }
00075
00076 # evalRatio --
00077 # Evaluate a rational function at a given coordinate
00078 #
00079 # Arguments:
00080 # ratio Rational function definition
00081 # x Coordinate
00082 # Result:
00083 # Value at x
00084 #
00085 proc ::math::rationalfunctions::evalRatio {ratio x} {
00086 if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00087 return -code error "Not a rational function"
00088 }
00089 if { ! [string is double $x] } {
00090 return -code error "Coordinate must be a real number"
00091 }
00092
00093 num = 0.0
00094 foreach c [lindex [lindex $ratio 1] 1] {
00095 num = [expr {$num*$x+$c}]
00096 }
00097
00098 den = 0.0
00099 foreach c [lindex [lindex $ratio 2] 1] {
00100 den = [expr {$den*$x+$c}]
00101 }
00102 return [expr {$num/double($den)}]
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 ret ::math::rationalfunctions::coeffsNumerator (type ratio) {
00114 if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00115 return -code error "Not a rational function"
00116 }
00117 set polyn [lindex $ratio 1]
00118 return [allCoeffsPolyn $polyn]
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 ret ::math::rationalfunctions::coeffsDenominator (type ratio) {
00130 if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00131 return -code error "Not a rational function"
00132 }
00133 set polyn [lindex $ratio 2]
00134 return [allCoeffsPolyn $polyn]
00135 }
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145 ret ::math::rationalfunctions::derivRatio (type ratio) {
00146 if { [lindex $ratio 0] != "RATIONAL_FUNCTION" } {
00147 return -code error "Not a rational function"
00148 }
00149 set num_polyn [lindex $ratio 1]
00150 set den_polyn [lindex $ratio 2]
00151 set num_deriv [derivPolyn $num_polyn]
00152 set den_deriv [derivPolyn $den_polyn]
00153 set num [subPolyn [multPolyn $num_deriv $den_polyn] \
00154 [multPolyn $den_deriv $num_polyn] ]
00155 set den [multPolyn $den_polyn $den_polyn]
00156
00157 return [list RATIONAL_FUNCTION $num $den]
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 ret ::math::rationalfunctions::addRatio (type ratio1 , type ratio2) {
00172 if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00173 set polyn1 [rationalFunction $ratio1 1.0]
00174 }
00175 if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00176 set ratio2 [rationalFunction $ratio1 1.0]
00177 }
00178 if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00179 [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00180 return -code error "Both arguments must be rational functions or a real number"
00181 }
00182
00183 set num1 [lindex $ratio1 1]
00184 set den1 [lindex $ratio1 2]
00185 set num2 [lindex $ratio2 1]
00186 set den2 [lindex $ratio2 2]
00187
00188 set newnum [addPolyn [multPolyn $num1 $den2] \
00189 [multPolyn $num2 $den1] ]
00190
00191 set newden [multPolyn $den1 $den2]
00192
00193 return [list RATIONAL_FUNCTION $newnum $newden]
00194 }
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 ret ::math::rationalfunctions::subRatio (type ratio1 , type ratio2) {
00208 if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00209 set polyn1 [rationalFunction $ratio1 1.0]
00210 }
00211 if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00212 set ratio2 [rationalFunction $ratio1 1.0]
00213 }
00214 if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00215 [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00216 return -code error "Both arguments must be rational functions or a real number"
00217 }
00218
00219 set num1 [lindex $ratio1 1]
00220 set den1 [lindex $ratio1 2]
00221 set num2 [lindex $ratio2 1]
00222 set den2 [lindex $ratio2 2]
00223
00224 set newnum [subPolyn [multPolyn $num1 $den2] \
00225 [multPolyn $num2 $den1] ]
00226
00227 set newden [multPolyn $den1 $den2]
00228
00229 return [list RATIONAL_FUNCTION $newnum $newden]
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 ret ::math::rationalfunctions::multRatio (type ratio1 , type ratio2) {
00244 if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00245 set polyn1 [rationalFunction $ratio1 1.0]
00246 }
00247 if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00248 set ratio2 [rationalFunction $ratio1 1.0]
00249 }
00250 if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00251 [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00252 return -code error "Both arguments must be rational functions or a real number"
00253 }
00254
00255 set num1 [lindex $ratio1 1]
00256 set den1 [lindex $ratio1 2]
00257 set num2 [lindex $ratio2 1]
00258 set den2 [lindex $ratio2 2]
00259
00260 set newnum [multPolyn $num1 $num2]
00261 set newden [multPolyn $den1 $den2]
00262
00263 return [list RATIONAL_FUNCTION $newnum $newden]
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 ret ::math::rationalfunctions::divRatio (type ratio1 , type ratio2) {
00278 if { [llength $ratio1] == 1 && [string is double -strict $ratio1] } {
00279 set polyn1 [rationalFunction $ratio1 1.0]
00280 }
00281 if { [llength $ratio2] == 1 && [string is double -strict $ratio2] } {
00282 set ratio2 [rationalFunction $ratio1 1.0]
00283 }
00284 if { [lindex $ratio1 0] != "RATIONAL_FUNCTION" ||
00285 [lindex $ratio2 0] != "RATIONAL_FUNCTION" } {
00286 return -code error "Both arguments must be rational functions or a real number"
00287 }
00288
00289 set num1 [lindex $ratio1 1]
00290 set den1 [lindex $ratio1 2]
00291 set num2 [lindex $ratio2 1]
00292 set den2 [lindex $ratio2 2]
00293
00294 set newnum [multPolyn $num1 $den2]
00295 set newden [multPolyn $num2 $den1]
00296
00297 return [list RATIONAL_FUNCTION $newnum $newden]
00298 }
00299
00300
00301
00302
00303 package provide math::rationalfunctions 1.0.1
00304
00305
00306
00307 if { 0 } {
00308 tcl = _precision 17
00309
00310 f1 = [::math::rationalfunctions::rationalFunction {1 2 3} {1 4}]
00311 f2 = [::math::rationalfunctions::rationalFunction {1 2 3 0} {1 4}]
00312 f3 = [::math::rationalfunctions::rationalFunction {0 0 0 0} {1}]
00313 f4 = [::math::rationalfunctions::rationalFunction {5 7} {1}]
00314 cmdf1 = [::math::rationalfunctions::ratioCmd {1 2 3} {1 4}]
00315
00316 foreach x {0 1 2 3 4 5} {
00317 puts "[::math::rationalfunctions::evalRatio $f1 $x] -- \
00318 [expr {(1.0+2.0*$x+3.0*$x*$x)/double(1.0+4.0*$x)}] -- \
00319 [$cmdf1 $x] -- [::math::rationalfunctions::evalRatio $f3 $x]"
00320 }
00321
00322 puts "All coefficients = [::math::rationalfunctions::coeffsNumerator $f2]"
00323 puts " [::math::rationalfunctions::coeffsDenominator $f2]"
00324
00325 puts "Derivative = [::math::rationalfunctions::derivRatio $f1]"
00326
00327 puts "Add: [::math::rationalfunctions::addRatio $f1 $f4]"
00328 puts "Add: [::math::rationalfunctions::addRatio $f4 $f1]"
00329 puts "Subtract: [::math::rationalfunctions::subRatio $f1 $f4]"
00330 puts "Multiply: [::math::rationalfunctions::multRatio $f1 $f4]"
00331
00332 f1 = [::math::rationalfunctions::rationalFunction {1 2 3} 1]
00333 f2 = [::math::rationalfunctions::rationalFunction {0 1} 1]
00334
00335 puts "Divide: [::math::rationalfunctions::divRatio $f1 $f2]"
00336
00337 f1 = [::math::rationalfunctions::rationalFunction {1 2 3} 1]
00338 f2 = [::math::rationalfunctions::rationalFunction {1 1} {1 2}]
00339
00340 puts "Divide: [::math::rationalfunctions::divRatio $f1 $f2]"
00341
00342 f1 = [::math::rationalfunctions::rationalFunction {1 2 3} 1]
00343 f2 = [::math::rationalfunctions::rationalFunction {0 1} {0 0 1}]
00344 f3 = [::math::rationalfunctions::divRatio $f2 $f1]
00345 coeffs = [::math::rationalfunctions::coeffsNumerator $f3]
00346 puts "Coefficients: $coeffs"
00347 f3 = [::math::rationalfunctions::divRatio $f1 $f2]
00348 coeffs = [::math::rationalfunctions::coeffsNumerator $f3]
00349 puts "Coefficients: $coeffs"
00350 f1 = [::math::rationalfunctions::rationalFunction {1 2 3} {1 2}]
00351 f2 = [::math::rationalfunctions::rationalFunction {0} {1}]
00352 f3 = [::math::rationalfunctions::divRatio $f2 $f1]
00353 coeffs = [::math::rationalfunctions::coeffsNumerator $f3]
00354 puts "Coefficients: $coeffs"
00355 puts "Eval null function: [::math::rationalfunctions::evalRatio $f2 1]"
00356 }
00357