00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 package require Tcl 8.4
00049 package require math::bignum
00050
00051
00052 catch {namespace delete ::math::bigfloat}
00053
00054
00055
00056
00057 namespace ::math::bigfloat {
00058
00059
00060 variable Log2
00061
00062 variable Pi
00063 variable _pi0
00064
00065 variable zero
00066 zero = [::math::bignum::fromstr 0]
00067 variable one
00068 one = [::math::bignum::fromstr 1]
00069 variable two
00070 two = [::math::bignum::fromstr 2]
00071 variable three
00072 three = [::math::bignum::fromstr 3]
00073 variable four
00074 four = [::math::bignum::fromstr 4]
00075 variable five
00076 five = [::math::bignum::fromstr 5]
00077 variable ten
00078 ten = [::math::bignum::fromstr 10]
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 ret ::math::bigfloat::abs (type number) {
00122 checkNumber number
00123 if {[isInt $number]} {
00124 # set sign to positive for a BigInt
00125 return [::math::bignum::abs $number]
00126 }
00127 # set sign to positive for a BigFloat into the Mantissa (index 1)
00128 lset number 1 [::math::bignum::abs [lindex $number 1]]
00129 return $number
00130 }
00131
00132
00133
00134
00135
00136 ret ::math::bigfloat::acos (type x) {
00137 # handy proc for checking datatype
00138 checkFloat x
00139 foreach {dummy entier exp delta} $x {break}
00140 set precision [expr {($exp<0)?(-$exp):1}]
00141 # acos(0.0)=Pi/2
00142 # 26/07/2005 : changed precision from decimal to binary
00143 # with the second parameter of pi command
00144 set piOverTwo [floatRShift [pi $precision 1]]
00145 if {[iszero $x]} {
00146 # $x is too close to zero -> acos(0)=PI/2
00147 return $piOverTwo
00148 }
00149 # acos(-x)= Pi/2 + asin(x)
00150 if {[::math::bignum::sign $entier]} {
00151 return [add $piOverTwo [asin [abs $x]]]
00152 }
00153 # we always use _asin to compute the result
00154 # but as it is a Taylor development, the value given to [_asin]
00155 # has to be a bit smaller than 1 ; by using that trick : acos(x)=asin(sqrt(1-x^2))
00156 # we can limit the entry of the Taylor development below 1/sqrt(2)
00157 if {[compare $x [fromstr 0.7071]]>0} {
00158 # x > sqrt(2)/2 : trying to make _asin converge quickly
00159 # creating 0 and 1 with the same precision as the entry
00160 variable one
00161 variable zero
00162 set fzero [list F $zero -$precision $one]
00163 set fone [list F [::math::bignum::lshift 1 $precision] \
00164 -$precision $one]
00165 # when $x is close to 1 (acos(1.0)=0.0)
00166 if {[equal $fone $x]} {
00167 return $fzero
00168 }
00169 if {[compare $fone $x]<0} {
00170 # the behavior assumed because acos(x) is not defined
00171 # when |x|>1
00172 error "acos on a number greater than 1"
00173 }
00174 # acos(x) = asin(sqrt(1 - x^2))
00175 # since 1 - cos(x)^2 = sin(x)^2
00176 # x> sqrt(2)/2 so x^2 > 1/2 so 1-x^2<1/2
00177 set x [sqrt [sub $fone [mul $x $x]]]
00178 # the parameter named x is smaller than sqrt(2)/2
00179 return [_asin $x]
00180 }
00181 # acos(x) = Pi/2 - asin(x)
00182 # x<sqrt(2)/2 here too
00183 return [sub $piOverTwo [_asin $x]]
00184 }
00185
00186
00187
00188
00189
00190 ret ::math::bigfloat::add (type a , type b) {
00191 checkNumber a b
00192 if {[isInt $a]} {
00193 if {[isInt $b]} {
00194 # intAdd adds two BigInts
00195 return [::math::bignum::add $a $b]
00196 }
00197 # adds the BigInt a to the BigFloat b
00198 return [addInt2Float $b $a]
00199 }
00200 if {[isInt $b]} {
00201 # ... and vice-versa
00202 return [addInt2Float $a $b]
00203 }
00204 # retrieving parameters from A and B
00205 foreach {dummy integerA expA deltaA} $a {break}
00206 foreach {dummy integerB expB deltaB} $b {break}
00207 # when we add two numbers which have different digit numbers (after the dot)
00208 # for example : 1.0 and 0.00001
00209 # We promote the one with the less number of digits (1.0) to the same level as
00210 # the other : so 1.00000.
00211 # that is why we shift left the number which has the greater exponent
00212 # But we do not forget the Delta parameter, which is lshift'ed too.
00213 if {$expA>$expB} {
00214 set diff [expr {$expA-$expB}]
00215 set integerA [::math::bignum::lshift $integerA $diff]
00216 set deltaA [::math::bignum::lshift $deltaA $diff]
00217 set integerA [::math::bignum::add $integerA $integerB]
00218 set deltaA [::math::bignum::add $deltaA $deltaB]
00219 return [normalize [list F $integerA $expB $deltaA]]
00220 } elseif {$expA==$expB} {
00221 # nothing to shift left
00222 return [normalize [list F [::math::bignum::add $integerA $integerB] \
00223 $expA [::math::bignum::add $deltaA $deltaB]]]
00224 } else {
00225 set diff [expr {$expB-$expA}]
00226 set integerB [::math::bignum::lshift $integerB $diff]
00227 set deltaB [::math::bignum::lshift $deltaB $diff]
00228 set integerB [::math::bignum::add $integerA $integerB]
00229 set deltaB [::math::bignum::add $deltaB $deltaA]
00230 return [normalize [list F $integerB $expA $deltaB]]
00231 }
00232 }
00233
00234
00235
00236
00237
00238
00239 ret ::math::bigfloat::addInt2Float (type a , type b) {
00240 # type checking
00241 checkFloat a
00242 if {![isInt $b]} {
00243 error "'$b' is not a BigInt"
00244 }
00245 # retrieving data from $a
00246 foreach {dummy integerA expA deltaA} $a {break}
00247 # to add an int to a BigFloat,...
00248 if {$expA>0} {
00249 # we have to put the integer integerA
00250 # to the level of zero exponent : 1e8 --> 100000000e0
00251 set shift $expA
00252 set integerA [::math::bignum::lshift $integerA $shift]
00253 set deltaA [::math::bignum::lshift $deltaA $shift]
00254 set integerA [::math::bignum::add $integerA $b]
00255 # we have to normalize, because we have shifted the mantissa
00256 # and the uncertainty left
00257 return [normalize [list F $integerA 0 $deltaA]]
00258 } elseif {$expA==0} {
00259 # integerA is already at integer level : float=(integerA)e0
00260 return [normalize [list F [::math::bignum::add $integerA $b] \
00261 0 $deltaA]]
00262 } else {
00263 # here we have something like 234e-2 + 3
00264 # we have to shift the integer left by the exponent |$expA|
00265 set b [::math::bignum::lshift $b [expr {-$expA}]]
00266 set integerA [::math::bignum::add $integerA $b]
00267 return [normalize [list F $integerA $expA $deltaA]]
00268 }
00269 }
00270
00271
00272
00273
00274
00275 ret ::math::bigfloat::asin (type x) {
00276 # type checking
00277 checkFloat x
00278 foreach {dummy entier exp delta} $x {break}
00279 if {$exp>-1} {
00280 error "not enough precision on input (asin)"
00281 }
00282 set precision [expr {-$exp}]
00283 # when x=0, return 0 at the same precision as the input was
00284 if {[iszero $x]} {
00285 variable one
00286 variable zero
00287 return [list F $zero -$precision $one]
00288 }
00289 # asin(-x)=-asin(x)
00290 if {[::math::bignum::sign $entier]} {
00291 return [opp [asin [abs $x]]]
00292 }
00293 # 26/07/2005 : changed precision from decimal to binary
00294 set piOverTwo [floatRShift [pi $precision 1]]
00295 # now a little trick : asin(x)=Pi/2-asin(sqrt(1-x^2))
00296 # so we can limit the entry of the Taylor development
00297 # to 1/sqrt(2)~0.7071
00298 # the comparison is : if x>0.7071 then ...
00299 if {[compare $x [fromstr 0.7071]]>0} {
00300 variable one
00301 set fone [list F [::math::bignum::lshift 1 $precision] \
00302 -$precision $one]
00303 # asin(1)=Pi/2 (with the same precision as the entry has)
00304 if {[equal $fone $x]} {
00305 return $piOverTwo
00306 }
00307 if {[compare $x $fone]>0} {
00308 error "asin on a number greater than 1"
00309 }
00310 # asin(x)=Pi/2-asin(sqrt(1-x^2))
00311 set x [sqrt [sub $fone [mul $x $x]]]
00312 return [sub $piOverTwo [_asin $x]]
00313 }
00314 return [normalize [_asin $x]]
00315 }
00316
00317
00318
00319
00320 ret ::math::bigfloat::_asin (type x) {
00321 # Taylor development
00322 # asin(x)=x + 1/2 x^3/3 + 3/2.4 x^5/5 + 3.5/2.4.6 x^7/7 + ...
00323 # into this iterative form :
00324 # asin(x)=x * (1 + 1/2 * x^2 * (1/3 + 3/4 *x^2 * (...
00325 # ...* (1/(2n-1) + (2n-1)/2n * x^2 / (2n+1))...)))
00326 # we show how is really computed the development :
00327 # we don't need to set a var with x^n or a product of integers
00328 # all we need is : x^2, 2n-1, 2n, 2n+1 and a few variables
00329 foreach {dummy mantissa exp delta} $x {break}
00330 set precision [expr {-$exp}]
00331 if {$precision+1<[::math::bignum::bits $mantissa]} {
00332 error "sinus greater than 1"
00333 }
00334 # precision is the number of after-dot digits
00335 set result $mantissa
00336 set delta_final $delta
00337 # resultat is the final result, and delta_final
00338 # will contain the uncertainty of the result
00339 # square is the square of the mantissa
00340 set square [intMulShift $mantissa $mantissa $precision]
00341 # dt is the uncertainty of Mantissa
00342 set dt [::math::bignum::add 1 [intMulShift $mantissa $delta [expr {$precision-1}]]]
00343 # these three are required to compute the fractions implicated into
00344 # the development (of Taylor, see former)
00345 variable one
00346 set num $one
00347 # two will be used into the loop
00348 variable two
00349 variable three
00350 set i $three
00351 set denom $two
00352 # the nth factor equals : $num/$denom* $mantissa/$i
00353 set delta [::math::bignum::add [::math::bignum::mul $delta $square] \
00354 [::math::bignum::mul $dt [::math::bignum::add $delta $mantissa]]]
00355 set delta [::math::bignum::add 1 [::math::bignum::rshift [::math::bignum::div \
00356 [::math::bignum::mul $delta $num] $denom] $precision]]
00357 # we do not multiply the Mantissa by $num right now because it is 1 !
00358 # but we have Mantissa=$x
00359 # and we want Mantissa*$x^2 * $num / $denom / $i
00360 set mantissa [intMulShift $mantissa $square $precision]
00361 set mantissa [::math::bignum::div $mantissa $denom]
00362 # do not forget the modified Taylor development :
00363 # asin(x)=x * (1 + 1/2*x^2*(1/3 + 3/4*x^2*(...*(1/(2n-1) + (2n-1)/2n*x^2/(2n+1))...)))
00364 # all we need is : x^2, 2n-1, 2n, 2n+1 and a few variables
00365 # $num=2n-1 $denom=2n $square=x^2 and $i=2n+1
00366 set mantissa_temp [::math::bignum::div $mantissa $i]
00367 set delta_temp [::math::bignum::add 1 [::math::bignum::div $delta $i]]
00368 # when the Mantissa increment is smaller than the Delta increment,
00369 # we would not get much precision by continuing the development
00370 while {![::math::bignum::iszero $mantissa_temp]} {
00371 # Mantissa = Mantissa * $num/$denom * $square
00372 # Add Mantissa/$i, which is stored in $mantissa_temp, to the result
00373 set result [::math::bignum::add $result $mantissa_temp]
00374 set delta_final [::math::bignum::add $delta_final $delta_temp]
00375 # here we have $two instead of [fromstr 2] (optimization)
00376 # num=num+2,i=i+2,denom=denom+2
00377 # because num=2n-1 denom=2n and i=2n+1
00378 set num [::math::bignum::add $num $two]
00379 set i [::math::bignum::add $i $two]
00380 set denom [::math::bignum::add $denom $two]
00381 # computes precisly the future Delta parameter
00382 set delta [::math::bignum::add [::math::bignum::mul $delta $square] \
00383 [::math::bignum::mul $dt [::math::bignum::add $delta $mantissa]]]
00384 set delta [::math::bignum::add 1 [::math::bignum::rshift [::math::bignum::div \
00385 [::math::bignum::mul $delta $num] $denom] $precision]]
00386 set mantissa [intMulShift $mantissa $square $precision]
00387 set mantissa [::math::bignum::div [::math::bignum::mul $mantissa $num] $denom]
00388 set mantissa_temp [::math::bignum::div $mantissa $i]
00389 set delta_temp [::math::bignum::add 1 [::math::bignum::div $delta $i]]
00390 }
00391 return [list F $result $exp $delta_final]
00392 }
00393
00394
00395
00396
00397 ret ::math::bigfloat::atan (type x) {
00398 checkFloat x
00399 variable one
00400 variable two
00401 variable three
00402 variable four
00403 variable zero
00404 foreach {dummy mantissa exp delta} $x {break}
00405 if {$exp>=0} {
00406 error "not enough precision to compute atan"
00407 }
00408 set precision [expr {-$exp}]
00409 # atan(0)=0
00410 if {[iszero $x]} {
00411 return [list F $zero -$precision $one]
00412 }
00413 # atan(-x)=-atan(x)
00414 if {[::math::bignum::sign $mantissa]} {
00415 return [opp [atan [abs $x]]]
00416 }
00417 # now x is strictly positive
00418 # at this moment, we are trying to limit |x| to a fair acceptable number
00419 # to ensure that Taylor development will converge quickly
00420 set float1 [list F [::math::bignum::lshift 1 $precision] -$precision $one]
00421 if {[compare $float1 $x]<0} {
00422 # compare x to 2.4142
00423 if {[compare $x [fromstr 2.4142]]<0} {
00424 # atan(x)=Pi/4 + atan((x-1)/(x+1))
00425 # as 1<x<2.4142 : (x-1)/(x+1)=1-2/(x+1) belongs to
00426 # the range : ]0,1-2/3.414[
00427 # that equals ]0,0.414[
00428 set pi_sur_quatre [div [pi $precision 1] $four]
00429 return [add $pi_sur_quatre [atan \
00430 [div [sub $x $float1] [add $x $float1]]]]
00431 }
00432 # atan(x)=Pi/2-atan(1/x)
00433 # 1/x < 1/2.414 so the argument is lower than 0.414
00434 set pi_over_two [div [pi $precision 1] $two]
00435 return [sub $pi_over_two [atan [div $float1 $x]]]
00436 }
00437 if {[compare $x [fromstr 0.4142]]>0} {
00438 # atan(x)=Pi/4 + atan((x-1)/(x+1))
00439 # x>0.420 so (x-1)/(x+1)=1 - 2/(x+1) > 1-2/1.414
00440 # > -0.414
00441 # x<1 so (x-1)/(x+1)<0
00442 set pi_sur_quatre [div [pi $precision 1] $four]
00443 return [add $pi_sur_quatre [atan \
00444 [div [sub $x $float1] [add $x $float1]]]]
00445 }
00446 # precision increment : to have less uncertainty
00447 # we add a little more precision so that the result would be more accurate
00448 # Taylor development : x - x^3/3 + x^5/5 - ... + (-1)^(n+1)*x^(2n-1)/(2n-1)
00449 # when we have n steps in Taylor development : the nth term is :
00450 # x^(2n-1)/(2n-1)
00451 # and the loss of precision is of 2n (n sums and n divisions)
00452 # this command is called with x<sqrt(2)-1
00453 # if we add an increment to the precision, say n:
00454 # (sqrt(2)-1)^(2n-1)/(2n-1) has to be lower than 2^(-precision-n-1)
00455 # (2n-1)*log(sqrt(2)-1)-log(2n-1)<-(precision+n+1)*log(2)
00456 # 2n(log(sqrt(2)-1)-log(sqrt(2)))<-(precision-1)*log(2)+log(2n-1)+log(sqrt(2)-1)
00457 # 2n*log(1-1/sqrt(2))<-(precision-1)*log(2)+log(2n-1)+log(2)/2
00458 # 2n/sqrt(2)>(precision-3/2)*log(2)-log(2n-1)
00459 # hence log(2n-1)<2n-1
00460 # n*sqrt(2)>(precision-1.5)*log(2)+1-2n
00461 # n*(sqrt(2)+2)>(precision-1.5)*log(2)+1
00462 set n [expr {int((log(2)*($precision-1.5)+1)/(sqrt(2)+2)+1)}]
00463 incr precision $n
00464 set mantissa [::math::bignum::lshift $mantissa $n]
00465 set delta [::math::bignum::lshift $delta $n]
00466 # end of adding precision increment
00467 # now computing Taylor development :
00468 # atan(x)=x - x^3/3 + x^5/5 - x^7/7 ... + (-1)^n*x^(2n+1)/(2n+1)
00469 # atan(x)=x * (1 - x^2 * (1/3 - x^2 * (1/5 - x^2 * (...*(1/(2n-1) - x^2 / (2n+1))...))))
00470 # what do we need to compute this ?
00471 # x^2 ($square), 2n+1 ($divider), $result, the nth term of the development ($t)
00472 # and the nth term multiplied by 2n+1 ($temp)
00473 # then we do this (with care keeping as much precision as possible):
00474 # while ($t <>0) :
00475 # $result=$result+$t
00476 # $temp=$temp * $square
00477 # $divider = $divider+2
00478 # $t=$temp/$divider
00479 # end-while
00480 set result $mantissa
00481 set delta_end $delta
00482 # we store the square of the integer (mantissa)
00483 set delta_square [::math::bignum::lshift $delta 1]
00484 set square [intMulShift $mantissa $mantissa $precision]
00485 # the (2n+1) divider
00486 set divider $three
00487 # computing precisely the uncertainty
00488 set delta [::math::bignum::add 1 [::math::bignum::rshift [::math::bignum::add \
00489 [::math::bignum::mul $delta_square $mantissa] \
00490 [::math::bignum::mul $delta $square]] $precision]]
00491 # temp contains (-1)^n*x^(2n+1)
00492 set temp [opp [intMulShift $mantissa $square $precision]]
00493 set t [::math::bignum::div $temp $divider]
00494 set dt [::math::bignum::add 1 [::math::bignum::div $delta $divider]]
00495 while {![::math::bignum::iszero $t]} {
00496 set result [::math::bignum::add $result $t]
00497 set delta_end [::math::bignum::add $delta_end $dt]
00498 set divider [::math::bignum::add $divider $two]
00499 set delta [::math::bignum::add 1 [::math::bignum::rshift [::math::bignum::add \
00500 [::math::bignum::mul $delta_square [abs $temp]] [::math::bignum::mul $delta \
00501 [::math::bignum::add $delta_square $square]]] $precision]]
00502 set temp [opp [intMulShift $temp $square $precision]]
00503 set t [::math::bignum::div $temp $divider]
00504 set dt [::math::bignum::add [::math::bignum::div $delta $divider] $one]
00505 }
00506 # we have to normalize because the uncertainty might be greater than 99
00507 # moreover it is the most often case
00508 return [normalize [list F $result [expr {$exp-$n}] $delta_end]]
00509 }
00510
00511
00512
00513
00514
00515
00516
00517 ret ::math::bigfloat::_atanfract (type integer , type precision) {
00518 # Taylor development : x - x^3/3 + x^5/5 - ... + (-1)^(n+1)*x^(2n-1)/(2n-1)
00519 # when we have n steps in Taylor development : the nth term is :
00520 # 1/denom^(2n+1)/(2n+1)
00521 # and the loss of precision is of 2n (n sums and n divisions)
00522 # this command is called with integer>=5
00523 #
00524 # We do not want to compute the Delta parameter, so we just
00525 # can increment precision (with lshift) in order for the result to be precise.
00526 # Remember : we compute atan2(1,$integer) with $precision bits
00527 # $integer has no Delta parameter as it is a BigInt, of course, so
00528 # theorically we could compute *any* number of digits.
00529 #
00530 # if we add an increment to the precision, say n:
00531 # (1/5)^(2n-1)/(2n-1) has to be lower than (1/2)^(precision+n-1)
00532 # Calculus :
00533 # log(left term) < log(right term)
00534 # log(1/left term) > log(1/right term)
00535 # (2n-1)*log(5)+log(2n-1)>(precision+n-1)*log(2)
00536 # n(2log(5)-log(2))>(precision-1)*log(2)-log(2n-1)+log(5)
00537 # -log(2n-1)>-(2n-1)
00538 # n(2log(5)-log(2)+2)>(precision-1)*log(2)+1+log(5)
00539 set n [expr {int((($precision-1)*log(2)+1+log(5))/(2*log(5)-log(2)+2)+1)}]
00540 incr precision $n
00541 # first term of the development : 1/integer
00542 set a [::math::bignum::div [::math::bignum::lshift 1 $precision] $integer]
00543 # 's' will contain the result
00544 set s $a
00545 # Taylor development : x - x^3/3 + x^5/5 - ... + (-1)^(n+1)*x^(2n-1)/(2n-1)
00546 # equals x (1 - x^2 * (1/3 + x^2 * (... * (1/(2n-3) + (-1)^(n+1) * x^2 / (2n-1))...)))
00547 # all we need to store is : 2n-1 ($denom), x^(2n+1) and x^2 ($square) and two results :
00548 # - the nth term => $u
00549 # - the nth term * (2n-1) => $t
00550 # + of course, the result $s
00551 set square [::math::bignum::mul $integer $integer]
00552 variable two
00553 variable three
00554 set denom $three
00555 # $t is (-1)^n*x^(2n+1)
00556 set t [opp [::math::bignum::div $a $square]]
00557 set u [::math::bignum::div $t $denom]
00558 # we break the loop when the current term of the development is null
00559 while {![::math::bignum::iszero $u]} {
00560 set s [::math::bignum::add $s $u]
00561 # denominator= (2n+1)
00562 set denom [::math::bignum::add $denom $two]
00563 # div $t by x^2
00564 set t [opp [::math::bignum::div $t $square]]
00565 set u [::math::bignum::div $t $denom]
00566 }
00567 # go back to the initial precision
00568 return [::math::bignum::rshift $s $n]
00569 }
00570
00571
00572
00573
00574
00575
00576
00577 ret ::math::bigfloat::ceil (type number) {
00578 checkFloat number
00579 set number [normalize $number]
00580 if {[iszero $number]} {
00581 # returns the BigInt 0
00582 variable zero
00583 return $zero
00584 }
00585 foreach {dummy integer exp delta} $number {break}
00586 if {$exp>=0} {
00587 error "not enough precision to perform rounding (ceil)"
00588 }
00589 # saving the sign ...
00590 set sign [::math::bignum::sign $integer]
00591 set integer [abs $integer]
00592 # integer part
00593 set try [::math::bignum::rshift $integer [expr {-$exp}]]
00594 if {$sign} {
00595 return [opp $try]
00596 }
00597 # fractional part
00598 if {![equal [::math::bignum::lshift $try [expr {-$exp}]] $integer]} {
00599 return [::math::bignum::add 1 $try]
00600 }
00601 return $try
00602 }
00603
00604
00605
00606
00607
00608
00609 ret ::math::bigfloat::checkFloat (type args) {
00610 foreach x $args {
00611 upvar $x n
00612 if {![isFloat $n]} {
00613 error "BigFloat expected : received '$n'"
00614 }
00615 }
00616 }
00617
00618
00619
00620
00621
00622 ret ::math::bigfloat::checkNumber (type args) {
00623 foreach i $args {
00624 upvar $i x
00625 if {![isInt $x] && ![isFloat $x]} {
00626 error "'$x' is not a number"
00627 }
00628 }
00629 }
00630
00631
00632
00633
00634
00635
00636 ret ::math::bigfloat::compare (type a , type b) {
00637 if {[isInt $a] && [isInt $b]} {
00638 return [::math::bignum::cmp $a $b]
00639 }
00640 checkFloat a b
00641 if {[equal $a $b]} {return 0}
00642 return [expr {([::math::bignum::sign [lindex [sub $a $b] 1]])?-1:1}]
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652 ret ::math::bigfloat::cos (type x) {
00653 checkFloat x
00654 foreach {dummy integer exp delta} $x {break}
00655 if {$exp>-2} {
00656 error "not enough precision on floating-point number"
00657 }
00658 set precision [expr {-$exp}]
00659 # cos(2kPi+x)=cos(x)
00660 foreach {n integer} [divPiQuarter $integer $precision] {break}
00661 # now integer>=0 and <Pi/2
00662 set d [expr {[tostr $n]%4}]
00663 # add trigonometric circle turns number to delta
00664 set delta [::math::bignum::add [abs $n] $delta]
00665 set signe 0
00666 # cos(Pi-x)=-cos(x)
00667 # cos(-x)=cos(x)
00668 # cos(Pi/2-x)=sin(x)
00669 switch -- $d {
00670 1 {set signe 1;set l [_sin2 $integer $precision $delta]}
00671 2 {set signe 1;set l [_cos2 $integer $precision $delta]}
00672 0 {set l [_cos2 $integer $precision $delta]}
00673 3 {set l [_sin2 $integer $precision $delta]}
00674 default {error "internal error"}
00675 }
00676 # precision -> exp (multiplied by -1)
00677 lset l 1 [expr {-([lindex $l 1])}]
00678 # set the sign
00679 set integer [lindex $l 0]
00680 ::math::bignum::setsign integer $signe
00681 lset l 0 $integer
00682 return [normalize [linsert $l 0 F]]
00683 }
00684
00685
00686
00687
00688
00689
00690
00691
00692 ret ::math::bigfloat::_cos2 (type x , type precision , type delta) {
00693 # precision bits after the dot
00694 set pi [_pi $precision]
00695 set pis4 [::math::bignum::rshift $pi 2]
00696 set pis2 [::math::bignum::rshift $pi 1]
00697 if {[::math::bignum::cmp $x $pis4]>=0} {
00698 # cos(Pi/2-x)=sin(x)
00699 set x [::math::bignum::sub $pis2 $x]
00700 set delta [::math::bignum::add 1 $delta]
00701 return [_sin $x $precision $delta]
00702 }
00703 return [_cos $x $precision $delta]
00704 }
00705
00706
00707
00708
00709
00710
00711
00712
00713 ret ::math::bigfloat::_cos (type x , type precision , type delta) {
00714 variable zero
00715 variable one
00716 variable two
00717 set float1 [::math::bignum::lshift $one $precision]
00718 # Taylor development follows :
00719 # cos(x)=1-x^2/2 + x^4/4! ... + (-1)^(2n)*x^(2n)/2n!
00720 # cos(x)= 1 - x^2/1.2 * (1 - x^2/3.4 * (... * (1 - x^2/(2n.(2n-1))...))
00721 # variables : $s (the Mantissa of the result)
00722 # $denom1 & $denom2 (2n-1 & 2n)
00723 # $x as the square of what is named x in 'cos(x)'
00724 set s $float1
00725 # 'd' is the uncertainty on x^2
00726 set d [::math::bignum::mul $x [::math::bignum::lshift $delta 1]]
00727 set d [::math::bignum::add 1 [::math::bignum::rshift $d $precision]]
00728 # x=x^2 (because in this Taylor development, there are only even powers of x)
00729 set x [intMulShift $x $x $precision]
00730 set denom1 $one
00731 set denom2 $two
00732 set t [opp [::math::bignum::rshift $x 1]]
00733 set delta $zero
00734 set dt $d
00735 while {![::math::bignum::iszero $t]} {
00736 set s [::math::bignum::add $s $t]
00737 set delta [::math::bignum::add $delta $dt]
00738 set denom1 [::math::bignum::add $denom1 $two]
00739 set denom2 [::math::bignum::add $denom2 $two]
00740 set dt [::math::bignum::rshift [::math::bignum::add [::math::bignum::mul $x $dt]\
00741 [::math::bignum::mul [::math::bignum::add $t $dt] $d]] $precision]
00742 set dt [::math::bignum::add 1 $dt]
00743 set t [intMulShift $x $t $precision]
00744 set t [opp [::math::bignum::div $t [::math::bignum::mul $denom1 $denom2]]]
00745 }
00746 return [list $s $precision $delta]
00747 }
00748
00749
00750
00751
00752 ret ::math::bigfloat::cotan (type x) {
00753 return [::math::bigfloat::div [::math::bigfloat::cos $x] [::math::bigfloat::sin $x]]
00754 }
00755
00756
00757
00758
00759
00760 ret ::math::bigfloat::deg2rad (type x) {
00761 checkFloat x
00762 set xLen [expr {-[lindex $x 2]}]
00763 if {$xLen<3} {
00764 error "number too loose to convert to radians"
00765 }
00766 set pi [pi $xLen 1]
00767 return [div [mul $x $pi] [::math::bignum::fromstr 180]]
00768 }
00769
00770
00771
00772
00773
00774
00775
00776
00777 ret ::math::bigfloat::divPiQuarter (type integer , type precision) {
00778 incr precision 2
00779 set integer [::math::bignum::lshift $integer 1]
00780 set dpi [_pi $precision]
00781 # modulo 2Pi
00782 foreach {n integer} [::math::bignum::divqr $integer $dpi] {break}
00783 # end modulo 2Pi
00784 set pi [::math::bignum::rshift $dpi 1]
00785 foreach {n integer} [::math::bignum::divqr $integer $pi] {break}
00786 # now divide by Pi/2
00787 # multiply n by 2
00788 set n [::math::bignum::lshift $n 1]
00789 # pis2=pi/2
00790 set pis2 [::math::bignum::rshift $pi 1]
00791 foreach {m integer} [::math::bignum::divqr $integer $pis2] {break}
00792 return [list [::math::bignum::add $n $m] [::math::bignum::rshift $integer 1]]
00793 }
00794
00795
00796
00797
00798
00799
00800 ret ::math::bigfloat::div (type a , type b) {
00801 variable one
00802 checkNumber a b
00803 # dispatch to an appropriate procedure
00804 if {[isInt $a]} {
00805 if {[isInt $b]} {
00806 return [::math::bignum::div $a $b]
00807 }
00808 error "trying to divide a BigInt by a BigFloat"
00809 }
00810 if {[isInt $b]} {return [divFloatByInt $a $b]}
00811 foreach {dummy integerA expA deltaA} $a {break}
00812 foreach {dummy integerB expB deltaB} $b {break}
00813 # computes the limits of the doubt (or uncertainty) interval
00814 set BMin [::math::bignum::sub $integerB $deltaB]
00815 set BMax [::math::bignum::add $integerB $deltaB]
00816 if {[::math::bignum::cmp $BMin $BMax]>0} {
00817 # swap BMin and BMax
00818 set temp $BMin
00819 set BMin $BMax
00820 set BMax $temp
00821 }
00822 # multiply by zero gives zero
00823 if {[::math::bignum::iszero $integerA]} {
00824 # why not return any number or the integer 0 ?
00825 # because there is an exponent that might be different between two BigFloats
00826 # 0.00 --> exp = -2, 0.000000 -> exp = -6
00827 return $a
00828 }
00829 # test of the division by zero
00830 if {[::math::bignum::sign $BMin]+[::math::bignum::sign $BMax]==1 || \
00831 [::math::bignum::iszero $BMin] || [::math::bignum::iszero $BMax]} {
00832 error "divide by zero"
00833 }
00834 # shift A because we need accuracy
00835 set l [math::bignum::bits $integerB]
00836 set integerA [::math::bignum::lshift $integerA $l]
00837 set deltaA [::math::bignum::lshift $deltaA $l]
00838 set exp [expr {$expA-$l-$expB}]
00839 # relative uncertainties (dX/X) are added
00840 # to give the relative uncertainty of the result
00841 # i.e. 3% on A + 2% on B --> 5% on the quotient
00842 # d(A/B)/(A/B)=dA/A + dB/B
00843 # Q=A/B
00844 # dQ=dA/B + dB*A/B*B
00845 # dQ is "delta"
00846 set delta [::math::bignum::div [::math::bignum::mul $deltaB \
00847 [abs $integerA]] [abs $integerB]]
00848 set delta [::math::bignum::div [::math::bignum::add\
00849 [::math::bignum::add 1 $delta]\
00850 $deltaA] [abs $integerB]]
00851 set quotient [::math::bignum::div $integerA $integerB]
00852 if {[::math::bignum::sign $integerB]+[::math::bignum::sign $integerA]==1} {
00853 set quotient [::math::bignum::sub $quotient 1]
00854 }
00855 return [normalize [list F $quotient $exp [::math::bignum::add $delta 1]]]
00856 }
00857
00858
00859
00860
00861
00862
00863
00864
00865 ret ::math::bigfloat::divFloatByInt (type a , type b) {
00866 variable one
00867 # type check
00868 checkFloat a
00869 if {![isInt $b]} {
00870 error "'$b' is not a BigInt"
00871 }
00872 foreach {dummy integer exp delta} $a {break}
00873 # zero divider test
00874 if {[::math::bignum::iszero $b]} {
00875 error "divide by zero"
00876 }
00877 # shift left for accuracy ; see other comments in [div] procedure
00878 set l [::math::bignum::bits $b]
00879 set integer [::math::bignum::lshift $integer $l]
00880 set delta [::math::bignum::lshift $delta $l]
00881 incr exp -$l
00882 set integer [::math::bignum::div $integer $b]
00883 # the uncertainty is always evaluated to the ceil value
00884 # and as an absolute value
00885 set delta [::math::bignum::add 1 [::math::bignum::div $delta [abs $b]]]
00886 return [normalize [list F $integer $exp $delta]]
00887 }
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 ret ::math::bigfloat::equal (type a , type b) {
00898 if {[isInt $a] && [isInt $b]} {
00899 return [expr {[::math::bignum::cmp $a $b]==0}]
00900 }
00901 # now a & b should only be BigFloats
00902 checkFloat a b
00903 foreach {dummy aint aexp adelta} $a {break}
00904 foreach {dummy bint bexp bdelta} $b {break}
00905 # set all Mantissas and Deltas to the same level (exponent)
00906 # with lshift
00907 set diff [expr {$aexp-$bexp}]
00908 if {$diff<0} {
00909 set diff [expr {-$diff}]
00910 set bint [::math::bignum::lshift $bint $diff]
00911 set bdelta [::math::bignum::lshift $bdelta $diff]
00912 } elseif {$diff>0} {
00913 set aint [::math::bignum::lshift $aint $diff]
00914 set adelta [::math::bignum::lshift $adelta $diff]
00915 }
00916 # compute limits of the number's doubt range
00917 set asupInt [::math::bignum::add $aint $adelta]
00918 set ainfInt [::math::bignum::sub $aint $adelta]
00919 set bsupInt [::math::bignum::add $bint $bdelta]
00920 set binfInt [::math::bignum::sub $bint $bdelta]
00921 # A & B are equal
00922 # if their doubt ranges overlap themselves
00923 if {[::math::bignum::cmp $bint $aint]==0} {
00924 return 1
00925 }
00926 if {[::math::bignum::cmp $bint $aint]>0} {
00927 set r [expr {[::math::bignum::cmp $asupInt $binfInt]>=0}]
00928 } else {
00929 set r [expr {[::math::bignum::cmp $bsupInt $ainfInt]>=0}]
00930 }
00931 return $r
00932 }
00933
00934
00935
00936
00937 ret ::math::bigfloat::exp (type x) {
00938 checkFloat x
00939 foreach {dummy integer exp delta} $x {break}
00940 if {$exp>=0} {
00941 # shift till exp<0 with respect to the internal representation
00942 # of the number
00943 incr exp
00944 set integer [::math::bignum::lshift $integer $exp]
00945 set delta [::math::bignum::lshift $delta $exp]
00946 set exp -1
00947 }
00948 set precision [expr {-$exp}]
00949 # add 8 bits of precision for safety
00950 incr precision 8
00951 set integer [::math::bignum::lshift $integer 8]
00952 set delta [::math::bignum::lshift $delta 8]
00953 set Log2 [_log2 $precision]
00954 foreach {new_exp integer} [::math::bignum::divqr $integer $Log2] {break}
00955 # new_exp = integer part of x/log(2)
00956 # integer = remainder
00957 # exp(K.log(2)+r)=2^K.exp(r)
00958 # so we just have to compute exp(r), r is small so
00959 # the Taylor development will converge quickly
00960 set delta [::math::bignum::add $delta $new_exp]
00961 foreach {integer delta} [_exp $integer $precision $delta] {break}
00962 set delta [::math::bignum::rshift $delta 8]
00963 incr precision -8
00964 # multiply by 2^K , and take care of the sign
00965 # example : X=-6.log(2)+0.01
00966 # exp(X)=exp(0.01)*2^-6
00967 if {![::math::bignum::iszero [::math::bignum::rshift [abs $new_exp] 30]]} {
00968 error "floating-point overflow due to exp"
00969 }
00970 set new_exp [tostr $new_exp]
00971 set exp [expr {$new_exp-$precision}]
00972 set delta [::math::bignum::add 1 $delta]
00973 return [normalize [list F [::math::bignum::rshift $integer 8] $exp $delta]]
00974 }
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987 ret ::math::bigfloat::_exp (type integer , type precision , type delta) {
00988 set oneShifted [::math::bignum::lshift 1 $precision]
00989 if {[::math::bignum::iszero $integer]} {
00990 # exp(0)=1
00991 return [list $oneShifted $delta]
00992 }
00993 set s [::math::bignum::add $oneShifted $integer]
00994 variable two
00995 set d [::math::bignum::add 1 [::math::bignum::div $delta $two]]
00996 set delta [::math::bignum::add $delta $delta]
00997 # dt = uncertainty on x^2
00998 set dt [::math::bignum::add 1 [intMulShift $d $integer $precision]]
00999 # t= x^2/2
01000 set t [intMulShift $integer $integer $precision]
01001 set t [::math::bignum::div $t $two]
01002 set denom $two
01003 while {![::math::bignum::iszero $t]} {
01004 # the sum is called 's'
01005 set s [::math::bignum::add $s $t]
01006 set delta [::math::bignum::add $delta $dt]
01007 # we do not have to keep trace of the factorial, we just iterate divisions
01008 set denom [::math::bignum::add 1 $denom]
01009 # add delta
01010 set d [::math::bignum::add 1 [::math::bignum::div $d $denom]]
01011 set dt [::math::bignum::add $dt $d]
01012 # get x^n from x^(n-1)
01013 set t [intMulShift $integer $t $precision]
01014 # here we divide
01015 set t [::math::bignum::div $t $denom]
01016 }
01017 return [list $s $delta]
01018 }
01019
01020
01021
01022 ret ::math::bigfloat::floatRShift (type float , optional n =1) {
01023 return [lset float 2 [expr {[lindex $float 2]-$n}]]
01024 }
01025
01026
01027
01028
01029
01030
01031
01032
01033 ret ::math::bigfloat::floor (type number) {
01034 variable zero
01035 checkFloat number
01036 set number [normalize $number]
01037 if {[::math::bignum::iszero $number]} {
01038 # returns the BigInt 0
01039 return $zero
01040 }
01041 foreach {dummy integer exp delta} $number {break}
01042 if {$exp>=0} {
01043 error "not enough precision to perform rounding (floor)"
01044 }
01045 # saving the sign ...
01046 set sign [::math::bignum::sign $integer]
01047 set integer [abs $integer]
01048 # integer part
01049 set try [::math::bignum::rshift $integer [expr {-$exp}]]
01050 # floor(n.xxxx)=n
01051 if {!$sign} {
01052 return $try
01053 }
01054 # floor(-n.xxxx)=-(n+1) when xxxx!=0
01055 if {![equal [::math::bignum::lshift $try [expr {-$exp}]] $integer]} {
01056 set try [::math::bignum::add 1 $try]
01057 }
01058 ::math::bignum::setsign try $sign
01059 return $try
01060 }
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 ret ::math::bigfloat::fromstr (type args) {
01076 if {[set string [lindex $args 0]]=="-base"} {
01077 if {[llength $args]!=3} {
01078 error "should be : fromstr -base base number"
01079 }
01080 # converts an integer i expressed in base b with : [fromstr b i]
01081 return [::math::bignum::fromstr [lindex $args 2] [lindex $args 1]]
01082 }
01083 # trailingZeros are zeros appended to the Mantissa (it is optional)
01084 set trailingZeros 0
01085 if {[llength $args]==2} {
01086 set trailingZeros [lindex $args 1]
01087 }
01088 if {$trailingZeros<0} {
01089 error "second argument has to be a positive integer"
01090 }
01091 # eliminate the sign problem
01092 # added on 05/08/2005
01093 # setting '$signe' to the sign of the number
01094 set string [string trimleft $string +]
01095 if {[string index $string 0]=="-"} {
01096 set signe 1
01097 set string2 [string range $string 1 end]
01098 } else {
01099 set signe 0
01100 set string2 $string
01101 }
01102 # integer case (not a floating-point number)
01103 if {[string is digit $string2]} {
01104 if {$trailingZeros!=0} {
01105 error "second argument not allowed with an integer"
01106 }
01107 # we have completed converting an integer to a BigInt
01108 # please note that most math::bigfloat procs accept BigInts as arguments
01109 return [::math::bignum::fromstr $string]
01110 }
01111 set string $string2
01112 # floating-point number : check for an exponent
01113 # scientific notation
01114 set tab [split $string e]
01115 if {[llength $tab]>2} {
01116 # there are more than one 'e' letter in the number
01117 error "syntax error in number : $string"
01118 }
01119 if {[llength $tab]==2} {
01120 set exp [lindex $tab 1]
01121 # now exp can look like +099 so you need to handle octal numbers
01122 # too bad...
01123 # find the sign (if any?)
01124 regexp {^[\+\-]?} $exp expsign
01125 # trim the number with left-side 0's
01126 set found [string length $expsign]
01127 set exp $expsign[string trimleft [string range $exp $found end] 0]
01128 set number [lindex $tab 0]
01129 } else {
01130 set exp 0
01131 set number [lindex $tab 0]
01132 }
01133 # a floating-point number may have a dot
01134 set tab [split $number .]
01135 if {[llength $tab]>2} {error "syntax error in number : $string"}
01136 if {[llength $tab]==2} {
01137 set number [join $tab ""]
01138 # increment by the number of decimals (after the dot)
01139 incr exp -[string length [lindex $tab 1]]
01140 }
01141 # this is necessary to ensure we can call fromstr (recursively) with
01142 # the mantissa ($number)
01143 if {![string is digit $number]} {
01144 error "$number is not a number"
01145 }
01146 # take account of trailing zeros
01147 incr exp -$trailingZeros
01148 # multiply $number by 10^$trailingZeros
01149 set number [::math::bignum::mul [::math::bignum::fromstr $number]\
01150 [tenPow $trailingZeros]]
01151 ::math::bignum::setsign number $signe
01152 # the F tags a BigFloat
01153 # a BigInt in internal representation begins by the sign
01154 # delta is 1 as a BigInt
01155 return [_fromstr $number $exp]
01156 }
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166 ret ::math::bigfloat::_fromstr (type number , type exp) {
01167 variable one
01168 variable five
01169 if {$exp==0} {
01170 return [list F $number 0 $one]
01171 }
01172 if {$exp>0} {
01173 # mul by 10^exp, and by 2^4, then normalize
01174 set number [::math::bignum::lshift $number 4]
01175 set exponent [tenPow $exp]
01176 set number [::math::bignum::mul $number $exponent]
01177 # normalize number*2^-4 +/- 2^4*10^exponent
01178 return [normalize [list F $number -4 [::math::bignum::lshift $exponent 4]]]
01179 }
01180 # now exp is negative or null
01181 # the closest power of 2 to the 'exp'th power of ten, but greater than it
01182 set binaryExp [expr {int(ceil(-$exp*log(10)/log(2)))+4}]
01183 # then compute n * 2^binaryExp / 10^(-exp)
01184 # (exp is negative)
01185 # equals n * 2^(binaryExp+exp) / 5^(-exp)
01186 set diff [expr {$binaryExp+$exp}]
01187 if {$diff<0} {
01188 error "internal error"
01189 }
01190 set fivePow [::math::bignum::pow $five [::math::bignum::fromstr [expr {-$exp}]]]
01191 set number [::math::bignum::div [::math::bignum::lshift $number \
01192 $diff] $fivePow]
01193 set delta [::math::bignum::div [::math::bignum::lshift 1 \
01194 $diff] $fivePow]
01195 return [normalize [list F $number [expr {-$binaryExp}] [::math::bignum::add $delta 1]]]
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206 ret ::math::bigfloat::fromdouble (type double , optional exp ={)} {
01207 set mantissa [lindex [split $double e] 0]
01208 # line added by SArnold on 05/08/2005
01209 set mantissa [string trimleft [string map {+ "" - ""} $mantissa] 0]
01210 precision = [string length [string map {. ""} $mantissa]]
01211 if { $exp != {} && [incr exp]>$precision } {
01212 return [fromstr $double [expr {$exp-$precision}]]
01213 } else {
01214
01215 return [fromstr $double]
01216 }
01217 }
01218
01219
01220
01221
01222
01223 ret ::math::bigfloat::int2float (type int , optional decimals =1) {
01224 # it seems like we need some kind of type handling
01225 # very odd in this Tcl world :-(
01226 if {![isInt $int]} {
01227 error "first argument is not an integer"
01228 }
01229 if {$decimals<1} {
01230 error "non-positive decimals number"
01231 }
01232 # the lowest number of decimals is 1, because
01233 # [tostr [fromstr 10.0]] returns 10.
01234 # (we lose 1 digit when converting back to string)
01235 set int [::math::bignum::mul $int [tenPow $decimals]]
01236 return [_fromstr $int [expr {-$decimals}]]
01237
01238 }
01239
01240
01241
01242
01243
01244
01245 ret ::math::bigfloat::intMulShift (type leftop , type rightop , type shift) {
01246 return [::math::bignum::rshift [::math::bignum::mul $leftop $rightop] $shift]
01247 }
01248
01249
01250
01251
01252 ret ::math::bigfloat::isFloat (type x) {
01253 # a BigFloat is a list of : "F" mantissa exponent delta
01254 if {[llength $x]!=4} {
01255 return 0
01256 }
01257 # the marker is the letter "F"
01258 if {[string equal [lindex $x 0] F]} {
01259 return 1
01260 }
01261 return 0
01262 }
01263
01264
01265
01266
01267 ret ::math::bigfloat::isInt (type n) {
01268 if {[llength $n]<3} {
01269 return 0
01270 }
01271 if {[string equal [lindex $n 0] bignum]} {
01272 return 1
01273 }
01274 return 0
01275 }
01276
01277
01278
01279
01280
01281
01282 ret ::math::bigfloat::iszero (type x) {
01283 if {[isInt $x]} {
01284 return [::math::bignum::iszero $x]
01285 }
01286 checkFloat x
01287 # now we do some interval rounding : if a number's interval englobs 0,
01288 # it is considered to be equal to zero
01289 foreach {dummy integer exp delta} $x {break}
01290 set integer [::math::bignum::abs $integer]
01291 if {[::math::bignum::cmp $delta $integer]>=0} {return 1}
01292 return 0
01293 }
01294
01295
01296
01297
01298
01299 ret ::math::bigfloat::log (type x) {
01300 checkFloat x
01301 foreach {dummy integer exp delta} $x {break}
01302 if {[::math::bignum::iszero $integer]||[::math::bignum::sign $integer]} {
01303 error "zero logarithm error"
01304 }
01305 if {[iszero $x]} {
01306 error "number is null"
01307 }
01308 set precision [::math::bignum::bits $integer]
01309 # uncertainty of the logarithm
01310 set delta [::math::bignum::add 1 [_logOnePlusEpsilon $delta $integer $precision]]
01311 # we got : x = 1xxxxxx (binary number with 'precision' bits) * 2^exp
01312 # we need : x = 0.1xxxxxx(binary) *2^(exp+precision)
01313 incr exp $precision
01314 foreach {integer deltaIncr} [_log $integer] {break}
01315 set delta [::math::bignum::add $delta $deltaIncr]
01316 # log(a * 2^exp)= log(a) + exp*log(2)
01317 # result = log(x) + exp*log(2)
01318 # as x<1 log(x)<0 but 'integer' (result of '_log') is the absolute value
01319 # that is why we substract $integer to log(2)*$exp
01320 set integer [::math::bignum::sub [::math::bignum::mul [_log2 $precision] \
01321 [set exp [::math::bignum::fromstr $exp]]] $integer]
01322 set delta [::math::bignum::add $delta [abs $exp]]
01323 return [normalize [list F $integer -$precision $delta]]
01324 }
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340 ret ::math::bigfloat::_logOnePlusEpsilon (type epsNum , type epsDenom , type precision) {
01341 if {[::math::bignum::cmp $epsNum $epsDenom]>=0} {
01342 error "number is null"
01343 }
01344 set s [::math::bignum::lshift $epsNum $precision]
01345 set s [::math::bignum::div $s $epsDenom]
01346 variable two
01347 set divider $two
01348 set t [::math::bignum::div [::math::bignum::mul $s $epsNum] $epsDenom]
01349 set u [::math::bignum::div $t $divider]
01350 # when u (the current term of the development) is zero, we have reached our goal
01351 # it has converged
01352 while {![::math::bignum::iszero $u]} {
01353 set s [::math::bignum::add $s $u]
01354 # divider = order of the term = 'n'
01355 set divider [::math::bignum::add 1 $divider]
01356 # t = (epsilon)^n
01357 set t [::math::bignum::div [::math::bignum::mul $t $epsNum] $epsDenom]
01358 # u = t/n = (epsilon)^n/n and is the nth term of the Taylor development
01359 set u [::math::bignum::div $t $divider]
01360 }
01361 return $s
01362 }
01363
01364
01365
01366
01367
01368 ret ::math::bigfloat::_log (type integer) {
01369 # the uncertainty is nbSteps with nbSteps<=nbBits
01370 # take nbSteps=nbBits (the worse case) and log(nbBits+increment)=increment
01371 set precision [::math::bignum::bits $integer]
01372 set n [expr {int(log($precision+2*log($precision)))}]
01373 set integer [::math::bignum::lshift $integer $n]
01374 incr precision $n
01375 variable three
01376 set delta $three
01377 # 1-epsilon=integer
01378 set integer [::math::bignum::sub [::math::bignum::lshift 1 $precision] $integer]
01379 set s $integer
01380 # t=x^2
01381 set t [intMulShift $integer $integer $precision]
01382 variable two
01383 set denom $two
01384 # u=x^2/2 (second term)
01385 set u [::math::bignum::div $t $denom]
01386 while {![::math::bignum::iszero $u]} {
01387 # while the current term is not zero, it has not converged
01388 set s [::math::bignum::add $s $u]
01389 set delta [::math::bignum::add 1 $delta]
01390 # t=x^n
01391 set t [intMulShift $t $integer $precision]
01392 # denom = n (the order of the current development term)
01393 set denom [::math::bignum::add 1 $denom]
01394 # u = x^n/n (the nth term of Taylor development)
01395 set u [::math::bignum::div $t $denom]
01396 }
01397 # shift right to restore the precision
01398 set delta [::math::bignum::add 1 [::math::bignum::rshift $delta $n]]
01399 return [list [::math::bignum::rshift $s $n] $delta]
01400 }
01401
01402
01403
01404
01405
01406
01407
01408 ret ::math::bigfloat::__log (type num , type denom , type precision) {
01409 # Please Note : we here need a precision increment, in order to
01410 # keep accuracy at $precision digits. If we just hold $precision digits,
01411 # each number being precise at the last digit +/- 1,
01412 # we would lose accuracy because small uncertainties add to themselves.
01413 # Example : 0.0001 + 0.0010 = 0.0011 +/- 0.0002
01414 # This is quite the same reason that made tcl_precision defaults to 12 :
01415 # internally, doubles are computed with 17 digits, but to keep precision
01416 # we need to limit our results to 12.
01417 # The solution : given a precision target, increment precision with a
01418 # computed value so that all digits of he result are exacts.
01419 #
01420 # p is the precision
01421 # pk is the precision increment
01422 # 2 power pk is also the maximum number of iterations
01423 # for a number close to 1 but lower than 1,
01424 # (denom-num)/denum is (in our case) lower than 1/5
01425 # so the maximum nb of iterations is for:
01426 # 1/5*(1+1/5*(1/2+1/5*(1/3+1/5*(...))))
01427 # the last term is 1/n*(1/5)^n
01428 # for the last term to be lower than 2^(-p-pk)
01429 # the number of iterations has to be
01430 # 2^(-pk).(1/5)^(2^pk) < 2^(-p-pk)
01431 # log(1/5).2^pk < -p
01432 # 2^pk > p/log(5)
01433 # pk > log(2)*log(p/log(5))
01434 # now set the variable n to the precision increment i.e. pk
01435 set n [expr {int(log(2)*log($precision/log(5)))+1}]
01436 incr precision $n
01437 # log(num/denom)=log(1-(denom-num)/denom)
01438 # log(1+x) = x + x^2/2 + x^3/3 + ... + x^n/n
01439 # = x(1 + x(1/2 + x(1/3 + x(...+ x(1/(n-1) + x/n)...))))
01440 set num [::math::bignum::fromstr [expr {$denom-$num}]]
01441 set denom [::math::bignum::fromstr $denom]
01442 # $s holds the result
01443 set s [::math::bignum::div [::math::bignum::lshift $num $precision] $denom]
01444 # $t holds x^n
01445 set t [::math::bignum::div [::math::bignum::mul $s $num] $denom]
01446 variable two
01447 set d $two
01448 # $u holds x^n/n
01449 set u [::math::bignum::div $t $d]
01450 while {![::math::bignum::iszero $u]} {
01451 set s [::math::bignum::add $s $u]
01452 # get x^n * x
01453 set t [::math::bignum::div [::math::bignum::mul $t $num] $denom]
01454 # get n+1
01455 set d [::math::bignum::add 1 $d]
01456 # then : $u = x^(n+1)/(n+1)
01457 set u [::math::bignum::div $t $d]
01458 }
01459 # see head of the proc : we return the value with its target precision
01460 return [::math::bignum::rshift $s $n]
01461 }
01462
01463
01464
01465
01466 ret ::math::bigfloat::__logbis (type precision) {
01467 set increment [expr {int(log($precision)/log(2)+1)}]
01468 incr precision $increment
01469 # ln(2)=3*ln(1-4/5)+ln(1-125/128)
01470 set a [__log 125 128 $precision]
01471 set b [__log 4 5 $precision]
01472 variable three
01473 set r [::math::bignum::add [::math::bignum::mul $b $three] $a]
01474 set ::math::bigfloat::Log2 [::math::bignum::rshift $r $increment]
01475 # formerly (when BigFloats were stored in ten radix) we had to compute log(10)
01476 # ln(10)=10.ln(1-4/5)+3*ln(1-125/128)
01477 }
01478
01479
01480
01481
01482
01483 ret ::math::bigfloat::_log2 (type precision) {
01484 variable Log2
01485 if {![info exists Log2]} {
01486 __logbis $precision
01487 } else {
01488 # the constant is cached and computed again when more precision is needed
01489 set l [::math::bignum::bits $Log2]
01490 if {$precision>$l} {
01491 __logbis $precision
01492 }
01493 }
01494 # return log(2) with 'precision' bits even when the cached value has more bits
01495 return [_round $Log2 $precision]
01496 }
01497
01498
01499
01500
01501
01502 ret ::math::bigfloat::mod (type a , type b) {
01503 checkNumber a b
01504 if {[isInt $a] && [isInt $b]} {return [::math::bignum::mod $a $b]}
01505 if {[isInt $a]} {error "trying to divide a BigInt by a BigFloat"}
01506 set quotient [div $a $b]
01507 # examples : fmod(3,2)=1 quotient=1.5
01508 # fmod(1,2)=1 quotient=0.5
01509 # quotient>0 and b>0 : get floor(quotient)
01510 # fmod(-3,-2)=-1 quotient=1.5
01511 # fmod(-1,-2)=-1 quotient=0.5
01512 # quotient>0 and b<0 : get floor(quotient)
01513 # fmod(-3,2)=-1 quotient=-1.5
01514 # fmod(-1,2)=-1 quotient=-0.5
01515 # quotient<0 and b>0 : get ceil(quotient)
01516 # fmod(3,-2)=1 quotient=-1.5
01517 # fmod(1,-2)=1 quotient=-0.5
01518 # quotient<0 and b<0 : get ceil(quotient)
01519 if {[sign $quotient]} {
01520 set quotient [ceil $quotient]
01521 } else {
01522 set quotient [floor $quotient]
01523 }
01524 return [sub $a [mul $quotient $b]]
01525 }
01526
01527
01528
01529
01530 ret ::math::bigfloat::mul (type a , type b) {
01531 checkNumber a b
01532 # dispatch the command to appropriate commands regarding types (BigInt & BigFloat)
01533 if {[isInt $a]} {
01534 if {[isInt $b]} {
01535 return [::math::bignum::mul $a $b]
01536 }
01537 return [mulFloatByInt $b $a]
01538 }
01539 if {[isInt $b]} {return [mulFloatByInt $a $b]}
01540 # now we are sure that 'a' and 'b' are BigFloats
01541 foreach {dummy integerA expA deltaA} $a {break}
01542 foreach {dummy integerB expB deltaB} $b {break}
01543 # 2^expA * 2^expB = 2^(expA+expB)
01544 set exp [expr {$expA+$expB}]
01545 # mantissas are multiplied
01546 set integer [::math::bignum::mul $integerA $integerB]
01547 # compute precisely the uncertainty
01548 set deltaAB [::math::bignum::mul $deltaA $deltaB]
01549 set deltaA [::math::bignum::mul [abs $integerB] $deltaA]
01550 set deltaB [::math::bignum::mul [abs $integerA] $deltaB]
01551 set delta [::math::bignum::add [::math::bignum::add $deltaA $deltaB] \
01552 [::math::bignum::add 1 $deltaAB]]
01553 # we have to normalize because 'delta' may be too big
01554 return [normalize [list F $integer $exp $delta]]
01555 }
01556
01557
01558
01559
01560 ret ::math::bigfloat::mulFloatByInt (type a , type b) {
01561 checkFloat a
01562 foreach {dummy integer exp delta} $a {break}
01563 if {![isInt $b]} {
01564 error "second argument expected to be a BigInt"
01565 }
01566 # Mantissa and Delta are simply multplied by $b
01567 set integer [::math::bignum::mul $integer $b]
01568 set delta [::math::bignum::mul $delta $b]
01569 # We normalize because Delta could have seriously increased
01570 return [normalize [list F $integer $exp $delta]]
01571 }
01572
01573
01574
01575
01576
01577
01578
01579
01580 ret ::math::bigfloat::normalize (type number) {
01581 checkFloat number
01582 foreach {dummy integer exp delta} $number {break}
01583 set l [::math::bignum::bits $delta]
01584 if {$l>8} {
01585 # next line : $l holds the supplementary size (in bits)
01586 incr l -8
01587 # now we can shift right by $l bits
01588 # always round upper the Delta
01589 set delta [::math::bignum::add 1 [::math::bignum::rshift $delta $l]]
01590 set integer [::math::bignum::rshift $integer $l]
01591 incr exp $l
01592 }
01593 return [list F $integer $exp $delta]
01594 }
01595
01596
01597
01598
01599
01600
01601 ret ::math::bigfloat::opp (type a) {
01602 checkNumber a
01603 if {[iszero $a]} {
01604 return $a
01605 }
01606 if {[isInt $a]} {
01607 ::math::bignum::setsign a [expr {![::math::bignum::sign $a]}]
01608 return $a
01609 }
01610 # recursive call
01611 lset a 1 [opp [lindex $a 1]]
01612 return $a
01613 }
01614
01615
01616
01617
01618
01619 ret ::math::bigfloat::pi (type precision , optional binary =0) {
01620 if {[llength $precision]>1} {
01621 if {[isInt $precision]} {
01622 set precision [tostr $precision]
01623 } else {
01624 error "'$precision' expected to be an integer"
01625 }
01626 }
01627 if {!$binary} {
01628 # convert decimal digit length into bit length
01629 set precision [expr {int(ceil($precision*log(10)/log(2)))}]
01630 }
01631 variable one
01632 return [list F [_pi $precision] -$precision $one]
01633 }
01634
01635
01636 ret ::math::bigfloat::_pi (type precision) {
01637 # the constant Pi begins with 3.xxx
01638 # so we need 2 digits to store the digit '3'
01639 # and then we will have precision+2 bits in the mantissa
01640 variable _pi0
01641 if {![info exists _pi0]} {
01642 set _pi0 [__pi $precision]
01643 }
01644 set lenPiGlobal [::math::bignum::bits $_pi0]
01645 if {$lenPiGlobal<$precision} {
01646 set _pi0 [__pi $precision]
01647 }
01648 return [::math::bignum::rshift $_pi0 [expr {[::math::bignum::bits $_pi0]-2-$precision}]]
01649 }
01650
01651
01652
01653
01654 ret ::math::bigfloat::__pi (type precision) {
01655 set safetyLimit 8
01656 # for safety and for the better precision, we do so ...
01657 incr precision $safetyLimit
01658 # formula found in the Math litterature
01659 # Pi/4 = 6.atan(1/18) + 8.atan(1/57) - 5.atan(1/239)
01660 set a [::math::bignum::mul [_atanfract [::math::bignum::fromstr 18] $precision] \
01661 [::math::bignum::fromstr 48]]
01662 set a [::math::bignum::add $a [::math::bignum::mul \
01663 [_atanfract [::math::bignum::fromstr 57] $precision] [::math::bignum::fromstr 32]]]
01664 set a [::math::bignum::sub $a [::math::bignum::mul \
01665 [_atanfract [::math::bignum::fromstr 239] $precision] [::math::bignum::fromstr 20]]]
01666 return [::math::bignum::rshift $a $safetyLimit]
01667 }
01668
01669
01670
01671
01672
01673 ret ::math::bigfloat::_round (type integer , type precision) {
01674 set shift [expr {[::math::bignum::bits $integer]-$precision}]
01675 # $result holds the shifted integer
01676 set result [::math::bignum::rshift $integer $shift]
01677 # $shift-1 is the bit just rights the last bit of the result
01678 # Example : integer=1000010 shift=2
01679 # => result=10000 and the tested bit is '1'
01680 if {[::math::bignum::testbit $integer [expr {$shift-1}]]} {
01681 # we round to the upper limit
01682 return [::math::bignum::add 1 $result]
01683 }
01684 return $result
01685 }
01686
01687
01688
01689
01690 ret ::math::bigfloat::pow (type a , type b) {
01691 checkNumber a
01692 if {![isInt $b]} {
01693 error "pow : exponent is not a positive integer"
01694 }
01695 # case where it is obvious that we should use the appropriate command
01696 # from math::bignum (added 5th March 2005)
01697 if {[isInt $a]} {
01698 return [::math::bignum::pow $a $b]
01699 }
01700 # algorithm : exponent=$b = Sum(i=0..n) b(i)2^i
01701 # $a^$b = $a^( b(0) + 2b(1) + 4b(2) + ... + 2^n*b(n) )
01702 # we have $a^(x+y)=$a^x * $a^y
01703 # then $a^$b = Product(i=0...n) $a^(2^i*b(i))
01704 # b(i) is boolean so $a^(2^i*b(i))= 1 when b(i)=0 and = $a^(2^i) when b(i)=1
01705 # then $a^$b = Product(i=0...n and b(i)=1) $a^(2^i) and 1 when $b=0
01706 variable one
01707 if {[::math::bignum::iszero $b]} {return $one}
01708 # $res holds the result
01709 set res $one
01710 while {1} {
01711 # at the beginning i=0
01712 # $remainder is b(i)
01713 set remainder [::math::bignum::testbit $b 0]
01714 # $b 'rshift'ed by 1 bit : i=i+1
01715 # so next time we will test bit b(i+1)
01716 set b [::math::bignum::rshift $b 1]
01717 # if b(i)=1
01718 if {$remainder} {
01719 # mul the result by $a^(2^i)
01720 # if i=0 we multiply by $a^(2^0)=$a^1=$a
01721 set res [mul $res $a]
01722 }
01723 # no more bits at '1' in $b : $res is the result
01724 if {[::math::bignum::iszero $b]} {
01725 if {[isInt $res]} {
01726 # we cannot (and should not) normalize an integer
01727 return $res
01728 }
01729 return [normalize $res]
01730 }
01731 # i=i+1 : $a^(2^(i+1)) = square of $a^(2^i)
01732 set a [mul $a $a]
01733 }
01734 }
01735
01736
01737
01738
01739 ret ::math::bigfloat::rad2deg (type x) {
01740 checkFloat x
01741 set xLen [expr {-[lindex $x 2]}]
01742 if {$xLen<3} {
01743 error "number too loose to convert to degrees"
01744 }
01745 set pi [pi $xLen 1]
01746 # $rad/Pi=$deg/180
01747 # so result in deg = $radians*180/Pi
01748 return [div [mul $x [::math::bignum::fromstr 180]] $pi]
01749 }
01750
01751
01752
01753
01754 ret ::math::bigfloat::round (type number) {
01755 checkFloat number
01756 #set number [normalize $number]
01757 # fetching integers (or BigInts) from the internal representation
01758 foreach {dummy integer exp delta} $number {break}
01759 if {[::math::bignum::iszero $integer]} {
01760 # returns the BigInt 0
01761 variable zero
01762 return $zero
01763 }
01764 if {$exp>=0} {
01765 error "not enough precision to round (in round)"
01766 }
01767 set exp [expr {-$exp}]
01768 # saving the sign, ...
01769 set sign [::math::bignum::sign $integer]
01770 set integer [abs $integer]
01771 # integer part of the number
01772 set try [::math::bignum::rshift $integer $exp]
01773 # first bit after the dot
01774 set way [::math::bignum::testbit $integer [expr {$exp-1}]]
01775 # delta is shifted so it gives the integer part of 2*delta
01776 set delta [::math::bignum::rshift $delta [expr {$exp-1}]]
01777 # when delta is too big to compute rounded value (
01778 if {![::math::bignum::iszero $delta]} {
01779 error "not enough precision to round (in round)"
01780 }
01781 if {$way} {
01782 set try [::math::bignum::add 1 $try]
01783 }
01784 # ... restore the sign now
01785 ::math::bignum::setsign try $sign
01786 return $try
01787 }
01788
01789
01790
01791
01792 ret ::math::bigfloat::roundshift (type integer , type n) {
01793 # $exp= 10^$n
01794 set exp [tenPow $n]
01795 foreach {result remainder} [::math::bignum::divqr $integer $exp] {}
01796 # $remainder belongs to the interval [0, $exp-1]
01797 # $remainder >= $exp/2 is the rounding condition
01798 # that is better expressed in this form :
01799 # $remainder*2 >= $exp , as we are treating integers, not rationals
01800 # left shift $remainder by 1 equals to multiplying by 2 and is much faster
01801 if {[::math::bignum::cmp $exp [::math::bignum::lshift $remainder 1]]<=0} {
01802 return [::math::bignum::add 1 $result]
01803 }
01804 return $result
01805 }
01806
01807
01808
01809
01810
01811 ret ::math::bigfloat::sign (type n) {
01812 if {[isInt $n]} {
01813 return [::math::bignum::sign $n]
01814 }
01815 # sign of 0=0
01816 if {[iszero $n]} {return 0}
01817 # the sign of the Mantissa, which is a BigInt
01818 return [::math::bignum::sign [lindex $n 1]]
01819 }
01820
01821
01822
01823
01824
01825 ret ::math::bigfloat::sin (type x) {
01826 checkFloat x
01827 foreach {dummy integer exp delta} $x {break}
01828 if {$exp>-2} {
01829 error "sin : not enough precision"
01830 }
01831 set precision [expr {-$exp}]
01832 # sin(2kPi+x)=sin(x)
01833 # $integer is now the modulo of the division of the mantissa by Pi/4
01834 # and $n is the quotient
01835 foreach {n integer} [divPiQuarter $integer $precision] {break}
01836 set delta [::math::bignum::add $delta $n]
01837 variable four
01838 set d [::math::bignum::mod $n $four]
01839 # now integer>=0
01840 # x = $n*Pi/4 + $integer and $n belongs to [0,3]
01841 # sin(2Pi-x)=-sin(x)
01842 # sin(Pi-x)=sin(x)
01843 # sin(Pi/2+x)=cos(x)
01844 set sign 0
01845 switch -- [tostr $d] {
01846 0 {set l [_sin2 $integer $precision $delta]}
01847 1 {set l [_cos2 $integer $precision $delta]}
01848 2 {set sign 1;set l [_sin2 $integer $precision $delta]}
01849 3 {set sign 1;set l [_cos2 $integer $precision $delta]}
01850 default {error "internal error"}
01851 }
01852 # $l is a list : {Mantissa Precision Delta}
01853 # precision --> the opposite of the exponent
01854 # 1.000 = 1000*10^-3 so exponent=-3 and precision=3 digits
01855 lset l 1 [expr {-([lindex $l 1])}]
01856 set integer [lindex $l 0]
01857 # the sign depends on the switch statement below
01858 ::math::bignum::setsign integer $sign
01859 lset l 0 $integer
01860 # we insert the Bigfloat tag (F) and normalize the final result
01861 return [normalize [linsert $l 0 F]]
01862 }
01863
01864 ret ::math::bigfloat::_sin2 (type x , type precision , type delta) {
01865 set pi [_pi $precision]
01866 # shift right by 1 = divide by 2
01867 # shift right by 2 = divide by 4
01868 set pis2 [::math::bignum::rshift $pi 1]
01869 set pis4 [::math::bignum::rshift $pi 2]
01870 if {[::math::bignum::cmp $x $pis4]>=0} {
01871 # sin(Pi/2-x)=cos(x)
01872 set delta [::math::bignum::add 1 $delta]
01873 set x [::math::bignum::sub $pis2 $x]
01874 return [_cos $x $precision $delta]
01875 }
01876 return [_sin $x $precision $delta]
01877 }
01878
01879
01880
01881
01882
01883
01884 ret ::math::bigfloat::_sin (type x , type precision , type delta) {
01885 # $s holds the result
01886 set s $x
01887 # sin(x) = x - x^3/3! + x^5/5! - ... + (-1)^n*x^(2n+1)/(2n+1)!
01888 # = x * (1 - x^2/(2*3) * (1 - x^2/(4*5) * (...* (1 - x^2/(2n*(2n+1)) )...)))
01889 # The second expression allows us to compute the less we can
01890
01891 # $double holds the uncertainty (Delta) of x^2 : 2*(Mantissa*Delta) + Delta^2
01892 # (Mantissa+Delta)^2=Mantissa^2 + 2*Mantissa*Delta + Delta^2
01893 set double [::math::bignum::rshift [::math::bignum::mul $x $delta] [expr {$precision-1}]]
01894 set double [::math::bignum::add [::math::bignum::add 1 $double] [::math::bignum::rshift \
01895 [::math::bignum::mul $delta $delta] $precision]]
01896 # $x holds the Mantissa of x^2
01897 set x [intMulShift $x $x $precision]
01898 set dt [::math::bignum::rshift [::math::bignum::add [::math::bignum::mul $x $delta] \
01899 [::math::bignum::mul [::math::bignum::add $s $delta] $double]] $precision]
01900 set dt [::math::bignum::add 1 $dt]
01901 # $t holds $s * -(x^2) / (2n*(2n+1))
01902 # mul by x^2
01903 set t [intMulShift $s $x $precision]
01904 variable two
01905 set denom2 $two
01906 variable three
01907 set denom3 $three
01908 # mul by -1 (opp) and divide by 2*3
01909 set t [opp [::math::bignum::div $t [::math::bignum::mul $denom2 $denom3]]]
01910 while {![::math::bignum::iszero $t]} {
01911 set s [::math::bignum::add $s $t]
01912 set delta [::math::bignum::add $delta $dt]
01913 # incr n => 2n --> 2n+2 and 2n+1 --> 2n+3
01914 set denom2 [::math::bignum::add $denom2 $two]
01915 set denom3 [::math::bignum::add $denom3 $two]
01916 # $dt is the Delta corresponding to $t
01917 # $double "" "" "" "" $x (x^2)
01918 # ($t+$dt) * ($x+$double) = $t*$x + ($dt*$x + $t*$double) + $dt*$double
01919 # Mantissa^ ^--------Delta-------------------^
01920 set dt [::math::bignum::rshift [::math::bignum::add [::math::bignum::mul $x $dt] \
01921 [::math::bignum::mul [::math::bignum::add $t $dt] $double]] $precision]
01922 set t [intMulShift $t $x $precision]
01923 # removed 2005/08/31 by sarnold75
01924 #set dt [::math::bignum::add $dt $double]
01925 set denom [::math::bignum::mul $denom2 $denom3]
01926 # now computing : div by -2n(2n+1)
01927 set dt [::math::bignum::add 1 [::math::bignum::div $dt $denom]]
01928 set t [opp [::math::bignum::div $t $denom]]
01929 }
01930 return [list $s $precision $delta]
01931 }
01932
01933
01934
01935
01936
01937 ret ::math::bigfloat::sqrt (type x) {
01938 variable one
01939 checkFloat x
01940 foreach {dummy integer exp delta} $x {break}
01941 # if x=0, return 0
01942 if {[iszero $x]} {
01943 variable zero
01944 # return zero, taking care of its precision ($exp)
01945 return [list F $zero $exp $one]
01946 }
01947 # we cannot get sqrt(x) if x<0
01948 if {[lindex $integer 0]<0} {
01949 error "negative sqrt input"
01950 }
01951 # (1+epsilon)^p = 1 + epsilon*(p-1) + epsilon^2*(p-1)*(p-2)/2! + ...
01952 # + epsilon^n*(p-1)*...*(p-n)/n!
01953 # sqrt(1 + epsilon) = (1 + epsilon)^(1/2)
01954 # = 1 - epsilon/2 - epsilon^2*3/(4*2!) - ...
01955 # - epsilon^n*(3*5*..*(2n-1))/(2^n*n!)
01956 # sqrt(1 - epsilon) = 1 + Sum(i=1..infinity) epsilon^i*(3*5*...*(2i-1))/(i!*2^i)
01957 # sqrt(n +/- delta)=sqrt(n) * sqrt(1 +/- delta/n)
01958 # so the uncertainty on sqrt(n +/- delta) equals sqrt(n) * (sqrt(1 - delta/n) - 1)
01959 # sqrt(1+eps) < sqrt(1-eps) because their logarithm compare as :
01960 # -ln(2)(1+eps) < -ln(2)(1-eps)
01961 # finally :
01962 # Delta = sqrt(n) * Sum(i=1..infinity) (delta/n)^i*(3*5*...*(2i-1))/(i!*2^i)
01963 # here we compute the second term of the product by _sqrtOnePlusEpsilon
01964 set delta [_sqrtOnePlusEpsilon $delta $integer]
01965 set intLen [::math::bignum::bits $integer]
01966 # removed 2005/08/31 by sarnold75, readded 2005/08/31
01967 set precision $intLen
01968 # intLen + exp = number of bits before the dot
01969 #set precision [expr {-$exp}]
01970 # square root extraction
01971 set integer [::math::bignum::lshift $integer $intLen]
01972 incr exp -$intLen
01973 incr intLen $intLen
01974 # there is an exponent 2^$exp : when $exp is odd, we would need to compute sqrt(2)
01975 # so we decrement $exp, in order to get it even, and we do not need sqrt(2) anymore !
01976 if {$exp&1} {
01977 incr exp -1
01978 set integer [::math::bignum::lshift $integer 1]
01979 incr intLen
01980 incr precision
01981 }
01982 # using a low-level (in math::bignum) root extraction procedure
01983 set integer [::math::bignum::sqrt $integer]
01984 # delta has to be multiplied by the square root
01985 set delta [::math::bignum::rshift [::math::bignum::mul $delta $integer] $precision]
01986 # round to the ceiling the uncertainty (worst precision, the fastest to compute)
01987 set delta [::math::bignum::add 1 $delta]
01988 # we are sure that $exp is even, see above
01989 return [normalize [list F $integer [expr {$exp/2}] $delta]]
01990 }
01991
01992
01993
01994
01995
01996
01997
01998 ret ::math::bigfloat::_sqrtOnePlusEpsilon (type delta , type integer) {
01999 # sqrt(1-x) - 1 = x/2 + x^2*3/(2^2*2!) + x^3*3*5/(2^3*3!) + ...
02000 # = x/2 * (1 + x*3/(2*2) * ( 1 + x*5/(2*3) *
02001 # (...* (1 + x*(2n-1)/(2n) ) )...)))
02002 variable one
02003 set l [::math::bignum::bits $integer]
02004 # to compute delta/integer we have to shift left to keep the same precision level
02005 # we have a better accuracy computing (delta << lg(integer))/integer
02006 # than computing (delta/integer) << lg(integer)
02007 set x [::math::bignum::div [::math::bignum::lshift $delta $l] $integer]
02008 variable four
02009 variable two
02010 # denom holds 2n
02011 set denom $four
02012 # x/2
02013 set result [::math::bignum::div $x $two]
02014 # x^2*3/(2!*2^2)
02015 variable three
02016 # numerator holds 2n-1
02017 set numerator $three
02018 set temp [::math::bignum::mul $result $delta]
02019 set temp [::math::bignum::div [::math::bignum::mul $temp $numerator] $integer]
02020 set temp [::math::bignum::add 1 [::math::bignum::div $temp $denom]]
02021 while {![::math::bignum::iszero $temp]} {
02022 set result [::math::bignum::add $result $temp]
02023 set numerator [::math::bignum::add $numerator $two]
02024 set denom [::math::bignum::add $two $denom]
02025 # n = n+1 ==> num=num+2 denom=denom+2
02026 # num=2n+1 denom=2n+2
02027 set temp [::math::bignum::mul [::math::bignum::mul $temp $delta] $numerator]
02028 set temp [::math::bignum::div [::math::bignum::div $temp $denom] $integer]
02029 }
02030 return $result
02031 }
02032
02033
02034
02035
02036 ret ::math::bigfloat::sub (type a , type b) {
02037 checkNumber a b
02038 if {[isInt $a] && [isInt $b]} {
02039 # the math::bignum::sub proc is designed to work with BigInts
02040 return [::math::bignum::sub $a $b]
02041 }
02042 return [add $a [opp $b]]
02043 }
02044
02045
02046
02047
02048 ret ::math::bigfloat::tan (type x) {
02049 return [::math::bigfloat::div [::math::bigfloat::sin $x] [::math::bigfloat::cos $x]]
02050 }
02051
02052
02053
02054
02055 ret ::math::bigfloat::tenPow (type n) {
02056 variable ten
02057 return [::math::bignum::pow $ten [::math::bignum::fromstr $n]]
02058 }
02059
02060
02061
02062
02063
02064
02065 ret ::math::bigfloat::todouble (type x) {
02066 global tcl_precision
02067 checkFloat x
02068 # get the string repr of x without the '+' sign
02069 set result [string trimleft [tostr $x] +]
02070 set minus ""
02071 if {[string index $result 0]=="-"} {
02072 set minus -
02073 set result [string range $result 1 end]
02074 }
02075 set l [split $result e]
02076 set exp 0
02077 if {[llength $l]==2} {
02078 # exp : x=Mantissa*10^Exp
02079 set exp [lindex $l 1]
02080 }
02081 # Mantissa = integerPart.fractionalPart
02082 set l [split [lindex $l 0] .]
02083 set integerPart [lindex $l 0]
02084 set integerLen [string length $integerPart]
02085 set fractionalPart [lindex $l 1]
02086 # The number of digits in Mantissa, excluding the dot and the leading zeros, of course
02087 set len [string length [set integer $integerPart$fractionalPart]]
02088 # Now Mantissa is stored in $integer
02089 if {$len>$tcl_precision} {
02090 set lenDiff [expr {$len-$tcl_precision}]
02091 # true when the number begins with a zero
02092 set zeroHead 0
02093 if {[string index $integer 0]==0} {
02094 incr lenDiff -1
02095 set zeroHead 1
02096 }
02097 set integer [tostr [roundshift [::math::bignum::fromstr $integer] $lenDiff]]
02098 if {$zeroHead} {
02099 set integer 0$integer
02100 }
02101 set len [string length $integer]
02102 if {$len<$integerLen} {
02103 set exp [expr {$integerLen-$len}]
02104 # restore the true length
02105 set integerLen $len
02106 }
02107 }
02108 # number = 'sign'*'integer'*10^'exp'
02109 if {$exp==0} {
02110 # no scientific notation
02111 set exp ""
02112 } else {
02113 # scientific notation
02114 set exp e$exp
02115 }
02116 # place the dot just before the index $integerLen in the Mantissa
02117 set result [string range $integer 0 [expr {$integerLen-1}]]
02118 append result .[string range $integer $integerLen end]
02119 # join the Mantissa with the sign before and the exponent after
02120 return $minus$result$exp
02121 }
02122
02123
02124
02125
02126 ret ::math::bigfloat::tostr (type number) {
02127 variable five
02128 if {[isInt $number]} {
02129 return [::math::bignum::tostr $number]
02130 }
02131 checkFloat number
02132 foreach {dummy integer exp delta} $number {break}
02133 if {[iszero $number]} {
02134 # we do not matter how much precision $number has :
02135 # it can be 0.0000000 or 0.0, the result is still the same : the "0" string
02136 # not anymore : 0.000 is not 0.0 !
02137 # return 0
02138 }
02139 if {$exp>0} {
02140 # the power of ten the closest but greater than 2^$exp
02141 # if it was lower than the power of 2, we would have more precision
02142 # than existing in the number
02143 set newExp [expr {int(ceil($exp*log(2)/log(10)))}]
02144 # 'integer' <- 'integer' * 2^exp / 10^newExp
02145 # equals 'integer' * 2^(exp-newExp) / 5^newExp
02146 set binExp [expr {$exp-$newExp}]
02147 if {$binExp<0} {
02148 # it cannot happen
02149 error "internal error"
02150 }
02151 # 5^newExp
02152 set fivePower [::math::bignum::pow $five [::math::bignum::fromstr $newExp]]
02153 # 'lshift'ing $integer by $binExp bits is like multiplying it by 2^$binExp
02154 # but much, much faster
02155 set integer [::math::bignum::div [::math::bignum::lshift $integer $binExp] \
02156 $fivePower]
02157 # $integer is the Mantissa - Delta should follow the same operations
02158 set delta [::math::bignum::div [::math::bignum::lshift $delta $binExp] $fivePower]
02159 set exp $newExp
02160 } elseif {$exp<0} {
02161 # the power of ten the closest but lower than 2^$exp
02162 # same remark about the precision
02163 set newExp [expr {int(floor(-$exp*log(2)/log(10)))}]
02164 # 'integer' <- 'integer' * 10^newExp / 2^(-exp)
02165 # equals 'integer' * 5^(newExp) / 2^(-exp-newExp)
02166 set fivePower [::math::bignum::pow $five \
02167 [::math::bignum::fromstr $newExp]]
02168 set binShift [expr {-$exp-$newExp}]
02169 # rshifting is like dividing by 2^$binShift, but faster as we said above about lshift
02170 set integer [::math::bignum::rshift [::math::bignum::mul $integer $fivePower] \
02171 $binShift]
02172 set delta [::math::bignum::rshift [::math::bignum::mul $delta $fivePower] \
02173 $binShift]
02174 set exp -$newExp
02175 }
02176 # saving the sign, to restore it into the result
02177 set sign [::math::bignum::sign $integer]
02178 set result [::math::bignum::abs $integer]
02179 # rounded 'integer' +/- 'delta'
02180 set up [::math::bignum::add $result $delta]
02181 set down [::math::bignum::sub $result $delta]
02182 if {[sign $up]^[sign $down]} {
02183 # $up>0 and $down<0 and vice-versa : then the number is considered equal to zero
02184 # delta <= 2**n (n = bits(delta))
02185 # 2**n <= 10**exp , then
02186 # exp >= n.log(2)/log(10)
02187 # delta <= 10**(n.log(2)/log(10))
02188 incr exp [expr {int(ceil([::math::bignum::bits $delta]*log(2)/log(10)))}]
02189 set result 0
02190 set isZero yes
02191 } else {
02192 # iterate until the convergence of the rounding
02193 # we incr $shift until $up and $down are rounded to the same number
02194 # at each pass we lose one digit of precision, so necessarly it will success
02195 for {set shift 1} {
02196 [::math::bignum::cmp [roundshift $up $shift] [roundshift $down $shift]]
02197 } {
02198 incr shift
02199 } {}
02200 incr exp $shift
02201 set result [::math::bignum::tostr [roundshift $up $shift]]
02202 set isZero no
02203 }
02204 set l [string length $result]
02205 # now formatting the number the most nicely for having a clear reading
02206 # would'nt we allow a number being constantly displayed
02207 # as : 0.2947497845e+012 , would we ?
02208 if {$exp>0} {
02209 # we display 423*10^6 as : 4.23e+8
02210 # Length of mantissa : $l
02211 # Increment exp by $l-1 because the first digit is placed before the dot,
02212 # the other ($l-1) digits following the dot.
02213 incr exp [incr l -1]
02214 set result [string index $result 0].[string range $result 1 end]
02215 append result "e+$exp"
02216 } elseif {$exp==0} {
02217 # it must have a dot to be a floating-point number (syntaxically speaking)
02218 append result .
02219 } else {
02220 set exp [expr {-$exp}]
02221 if {$exp < $l} {
02222 # we can display the number nicely as xxxx.yyyy*
02223 # the problem of the sign is solved finally at the bottom of the proc
02224 set n [string range $result 0 end-$exp]
02225 incr exp -1
02226 append n .[string range $result end-$exp end]
02227 set result $n
02228 } elseif {$l==$exp} {
02229 # we avoid to use the scientific notation
02230 # because it is harder to read
02231 set result "0.$result"
02232 } else {
02233 # ... but here there is no choice, we should not represent a number
02234 # with more than one leading zero
02235 set result [string index $result 0].[string range $result 1 end]e-[expr {$exp-$l+1}]
02236 }
02237 }
02238 # restore the sign : we only put a minus on numbers that are different from zero
02239 if {$sign==1 && !$isZero} {set result "-$result"}
02240 return $result
02241 }
02242
02243
02244
02245
02246
02247
02248
02249
02250
02251 ret ::math::bigfloat::cosh (type x) {
02252 # cosh(x) = (exp(x)+exp(-x))/2
02253 # dividing by 2 is done faster by 'rshift'ing
02254 return [floatRShift [add [exp $x] [exp [opp $x]]] 1]
02255 }
02256
02257
02258
02259
02260 ret ::math::bigfloat::sinh (type x) {
02261 # sinh(x) = (exp(x)-exp(-x))/2
02262 # dividing by 2 is done faster by 'rshift'ing
02263 return [floatRShift [sub [exp $x] [exp [opp $x]]] 1]
02264 }
02265
02266
02267
02268
02269 ret ::math::bigfloat::tanh (type x) {
02270 set up [exp $x]
02271 set down [exp [opp $x]]
02272 # tanh(x)=sinh(x)/cosh(x)= (exp(x)-exp(-x))/2/ [(exp(x)+exp(-x))/2]
02273 # =(exp(x)-exp(-x))/(exp(x)+exp(-x))
02274 # =($up-$down)/($up+$down)
02275 return [div [sub $up $down] [add $up $down]]
02276 }
02277
02278
02279 namespace ::math::bigfloat {
02280 foreach function {
02281 add mul sub div mod pow
02282 iszero compare equal
02283 fromstr tostr fromdouble todouble
02284 int2float isInt isFloat
02285 exp log sqrt round ceil floor
02286 sin cos tan cotan asin acos atan
02287 cosh sinh tanh abs opp
02288 pi deg2rad rad2deg
02289 } {
02290 namespace export $function
02291 }
02292 }
02293
02294
02295
02296
02297 package provide math::bigfloat 1.2.1
02298