bigfloat.tcl

Go to the documentation of this file.
00001 /* */
00002 /*  BigFloat for Tcl*/
00003 /*  Copyright (C) 2003-2005  ARNOLD Stephane*/
00004 /* */
00005 /*  BIGFLOAT LICENSE TERMS*/
00006 /* */
00007 /*  This software is copyrighted by Stephane ARNOLD, (stephanearnold <at> yahoo.fr).*/
00008 /*  The following terms apply to all files associated*/
00009 /*  with the software unless explicitly disclaimed in individual files.*/
00010 /* */
00011 /*  The authors hereby grant permission to use, copy, modify, distribute,*/
00012 /*  and license this software and its documentation for any purpose, provided*/
00013 /*  that existing copyright notices are retained in all copies and that this*/
00014 /*  notice is included verbatim in any distributions. No written agreement,*/
00015 /*  license, or royalty fee is required for any of the authorized uses.*/
00016 /*  Modifications to this software may be copyrighted by their authors*/
00017 /*  and need not follow the licensing terms described here, provided that*/
00018 /*  the new terms are clearly indicated on the first page of each file where*/
00019 /*  they apply.*/
00020 /* */
00021 /*  IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY*/
00022 /*  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES*/
00023 /*  ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY*/
00024 /*  DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE*/
00025 /*  POSSIBILITY OF SUCH DAMAGE.*/
00026 /* */
00027 /*  THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,*/
00028 /*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,*/
00029 /*  FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE*/
00030 /*  IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE*/
00031 /*  NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR*/
00032 /*  MODIFICATIONS.*/
00033 /* */
00034 /*  GOVERNMENT USE: If you are acquiring this software on behalf of the*/
00035 /*  U.S. government, the Government shall have only "Restricted Rights"*/
00036 /*  in the software and related documentation as defined in the Federal*/
00037 /*  Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you*/
00038 /*  are acquiring the software on behalf of the Department of Defense, the*/
00039 /*  software shall be classified as "Commercial Computer Software" and the*/
00040 /*  Government shall have only "Restricted Rights" as defined in Clause*/
00041 /*  252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the*/
00042 /*  authors grant the U.S. Government and others acting in its behalf*/
00043 /*  permission to use and distribute the software in accordance with the*/
00044 /*  terms specified in this license.*/
00045 /* */
00046 /* */
00047 
00048 package require Tcl 8.4
00049 package require math::bignum
00050 
00051 /*  this line helps when I want to source this file again and again*/
00052 catch {namespace delete ::math::bigfloat}
00053 
00054 /*  private namespace*/
00055 /*  this software works only with Tcl v8.4 and higher*/
00056 /*  it is using the package math::bignum*/
00057 namespace ::math::bigfloat {
00058     /*  cached constants*/
00059     /*  ln(2) with arbitrary precision*/
00060     variable Log2
00061     /*  Pi with arb. precision*/
00062     variable Pi
00063     variable _pi0
00064     /*  some constants (bignums) : {0 1 2 3 4 5 10}*/
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 /*  procedures that handle floating-point numbers*/
00086 /*  these procedures are sorted by name (after eventually removing the underscores)*/
00087 /*  */
00088 /*  BigFloats are internally represented as a list :*/
00089 /*  {"F" Mantissa Exponent Delta} where "F" is a character which determins*/
00090 /*  the datatype, Mantissa and Delta are two Big integers and Exponent a raw integer.*/
00091 /* */
00092 /*  The BigFloat value equals to (Mantissa +/- Delta)*2^Exponent*/
00093 /*  So the internal representation is binary, but trying to get as close as possible to*/
00094 /*  the decimal one.*/
00095 /*  When calling fromstr, the Delta parameter is set to the value of the last decimal digit.*/
00096 /*  Example : 1.50 belongs to [1.49,1.51], but internally Delta is probably not equal to 1,*/
00097 /*  because of the binary representation.*/
00098 /*  */
00099 /*  So Mantissa and Delta are not limited in size, but in practice Delta is kept under*/
00100 /*  2^32 by the 'normalize' procedure, to avoid a never-ended growth of memory used.*/
00101 /*  Indeed, when you perform some computations, the Delta parameter (which represent*/
00102 /*  the uncertainty on the value of the Mantissa) may increase.*/
00103 /*  Exponent, as a classic integer, is limited to the interval [-2147483648,2147483647]*/
00104 
00105 /*  Retrieving the parameters of a BigFloat is often done with that command :*/
00106 /*  foreach {dummy int exp delta} $bigfloat {break}*/
00107 /*  (dummy is not used, it is just used to get the "F" marker).*/
00108 /*  The isInt, isFloat, checkNumber and checkFloat procedures are used*/
00109 /*  to check data types*/
00110 /* */
00111 /*  Taylor development are often used to compute the analysis functions (like exp(),log()...)*/
00112 /*  To learn how it is done in practice, take a look at ::math::bigfloat::_asin*/
00113 /*  While doing computation on Mantissas, we do not care about the last digit,*/
00114 /*  because if we compute wisely Deltas, the digits that remain will be exact.*/
00115 /* */
00116 
00117 
00118 /* */
00119 /*  returns the absolute value*/
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 /*  arccosinus of a BigFloat*/
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 /*  returns A + B*/
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 /*  returns the sum A(BigFloat) + B(BigInt)*/
00236 /*  the greatest advantage of this method is that the uncertainty*/
00237 /*  of the result remains unchanged, in respect to the entry's uncertainty (deltaA)*/
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 /*  arcsinus of a BigFloat*/
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 /*  _asin : arcsinus of numbers between 0 and +1*/
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 /*  arctangent : returns atan(x)*/
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 /*  compute atan(1/integer) at a given precision*/
00514 /*  this proc is only used to compute Pi*/
00515 /*  it is using the same Taylor development as [atan]*/
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 /*  returns the integer part of a BigFloat, as a BigInt*/
00574 /*  the result is the same one you would have*/
00575 /*  if you had called [expr {ceil($x)}]*/
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 /*  checks each variable to be a BigFloat*/
00607 /*  arguments : each argument is the name of a variable to be checked*/
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 /*  checks if each number is either a BigFloat or a BigInt*/
00620 /*  arguments : each argument is the name of a variable to be checked*/
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 /*  returns 0 if A and B are equal, else returns 1 or -1*/
00634 /*  accordingly to the sign of (A - B)*/
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 /*  gets cos(x)*/
00650 /*  throws an error if there is not enough precision on the input*/
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 /*  compute cos(x) where 0<=x<Pi/2*/
00687 /*  returns : a list formed with :*/
00688 /*  1. the mantissa*/
00689 /*  2. the precision (opposite of the exponent)*/
00690 /*  3. the uncertainty (doubt range)*/
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 /*  compute cos(x) where 0<=x<Pi/4*/
00708 /*  returns : a list formed with :*/
00709 /*  1. the mantissa*/
00710 /*  2. the precision (opposite of the exponent)*/
00711 /*  3. the uncertainty (doubt range)*/
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 /*  cotangent : the trivial algorithm is used*/
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 /*  converts angles from degrees to radians*/
00758 /*  deg/180=rad/Pi*/
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 /*  private proc to get : x modulo Pi/2*/
00774 /*  and the quotient (x divided by Pi/2)*/
00775 /*  used by cos , sin & others*/
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 /*  divide A by B and returns the result*/
00798 /*  throw error : divide by zero*/
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 /*  divide a BigFloat A by a BigInt B*/
00863 /*  throw error : divide by zero*/
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 /*  returns 1 if A and B are equal, 0 otherwise*/
00895 /*  IN : a, b (BigFloats)*/
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 /*  returns exp(X) where X is a BigFloat*/
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 /*  private procedure to compute exponentials*/
00979 /*  using Taylor development of exp(x) :*/
00980 /*  exp(x)=1+ x + x^2/2 + x^3/3! +...+x^n/n!*/
00981 /*  input : integer (the mantissa)*/
00982 /*          precision (the number of decimals)*/
00983 /*          delta (the doubt limit, or uncertainty)*/
00984 /*  returns a list : 1. the mantissa of the result*/
00985 /*                   2. the doubt limit, or uncertainty*/
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 /*  divide a BigFloat by 2 power 'n'*/
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 /*  procedure floor : identical to [expr floor($x)] in functionality*/
01030 /*  arguments : number IN (a BigFloat)*/
01031 /*  returns : the floor value as a BigInt*/
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 /*  returns a list formed by an integer and an exponent*/
01065 /*  x = (A +/- C) * 10 power B*/
01066 /*  return [list "F" A B C] (where F is the BigFloat tag)*/
01067 /*  A and C are BigInts, B is a raw integer*/
01068 /*  return also a BigInt when there is neither a dot, nor a 'e' exponent*/
01069 /* */
01070 /*  arguments : -base base integer*/
01071 /*           or integer*/
01072 /*           or float*/
01073 /*           or float trailingZeros*/
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 /*  private procedure to transform decimal floats into binary ones*/
01160 /*  IN :*/
01161 /*      - number : a BigInt representing the Mantissa*/
01162 /*      - exp : the decimal exponent (a simple integer)*/
01163 /*  OUT :*/
01164 /*      $number * 10^$exp, as the internal binary representation of a BigFloat*/
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 /*  fromdouble :*/
01201 /*  like fromstr, but for a double scalar value*/
01202 /*  arguments :*/
01203 /*  double - the number to convert to a BigFloat*/
01204 /*  exp (optional) - the total number of digits*/
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         /*  tests have failed : not enough precision or no exp argument*/
01215         return [fromstr $double]
01216     }
01217 }
01218 
01219 
01220 /* */
01221 /*  converts a BigInt into a BigFloat with a given decimal precision*/
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 /*  multiplies 'leftop' by 'rightop' and rshift the result by 'shift'*/
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 /*  returns 1 if x is a BigFloat, 0 elsewhere*/
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 /*  checks that n is a BigInt (a number create by math::bignum::fromstr)*/
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 /*  returns 1 if x is null, 0 otherwise*/
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 /*  compute log(X)*/
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 /*  compute log(1-epsNum/epsDenom)=log(1-'epsilon')*/
01329 /*  Taylor development gives -x -x^2/2 -x^3/3 -x^4/4 ...*/
01330 /*  used by 'log' command because log(x+/-epsilon)=log(x)+log(1+/-(epsilon/x))*/
01331 /*  so the uncertainty equals abs(log(1-epsilon/x))*/
01332 /*  ================================================*/
01333 /*  arguments :*/
01334 /*  epsNum IN (the numerator of epsilon)*/
01335 /*  epsDenom IN (the denominator of epsilon)*/
01336 /*  precision IN (the number of bits after the dot)*/
01337 /* */
01338 /*  'epsilon' = epsNum*2^-precision/epsDenom*/
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 /*  compute log(0.xxxxxxxx) : log(1-epsilon)=-eps-eps^2/2-eps^3/3...-eps^n/n*/
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 /*  computes log(num/denom) with 'precision' bits*/
01404 /*  used to compute some analysis constants with a given accuracy*/
01405 /*  you might not call this procedure directly : it assumes 'num/denom'>4/5*/
01406 /*  and 'num/denom'<1*/
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 /*  computes log(2) with 'precision' bits and caches it into a namespace variable*/
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 /*  retrieves log(2) with 'precision' bits ; the result is cached*/
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 /*  returns A modulo B (like with fmod() math function)*/
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 /*  returns A times B*/
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 /*  returns A times B, where B is a positive integer*/
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 /*  normalizes a number : Delta (accuracy of the BigFloat)*/
01575 /*  has to be limited, because the memory use increase*/
01576 /*  quickly when we do some computations, as the Mantissa and Delta*/
01577 /*  increase together*/
01578 /*  The solution : keep the size of Delta under 9 bits*/
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 /*  returns -A (the opposite)*/
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 /*  gets Pi with precision bits*/
01617 /*  after the dot (after you call [tostr] on the result)*/
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 /*  computes an integer representing Pi in binary radix, with precision bits*/
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 /*  shift right an integer until it haves $precision bits*/
01671 /*  round at the same time*/
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 /*  returns A power B, where B is a positive integer*/
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 /*  converts angles for radians to degrees*/
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 /*  retourne la partie entière (ou 0) du nombre "number"*/
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 /*  round and divide by 10^n*/
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 /*  gets the sign of either a bignum, or a BitFloat*/
01809 /*  we keep the bignum convention : 0 for positive, 1 for negative*/
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 /*  gets sin(x)*/
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 /*  sin(x) with 'x' lower than Pi/4 and positive*/
01881 /*  'x' is the Mantissa - 'delta' is Delta*/
01882 /*  'precision' is the opposite of the exponent*/
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 /*  procedure for extracting the square root of a BigFloat*/
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 /*  compute abs(sqrt(1-delta/integer)-1)*/
01996 /*  the returned value is a relative uncertainty*/
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 /*  substracts B to A*/
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 /*  tangent (trivial algorithm)*/
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 /*  returns a power of ten*/
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 /*  converts a BigInt to a double (basic floating-point type)*/
02063 /*  with respect to the global variable 'tcl_precision'*/
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 /*  converts a number stored as a list to a string in which all digits are true*/
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 /*  PART IV*/
02245 /*  HYPERBOLIC FUNCTIONS*/
02246 /* */
02247 
02248 /* */
02249 /*  hyperbolic cosinus*/
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 /*  hyperbolic sinus*/
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 /*  hyperbolic tangent*/
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 /*  exporting public interface*/
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 /*  (AM) No "namespace import" - this should be left to the user!*/
02295 /* namespace import ::math::bigfloat::**/
02296 
02297 package provide math::bigfloat 1.2.1
02298 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1