1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
|
[manpage_begin math::bigfloat n 1.2]
[copyright {2004-2005 Stephane Arnold <stephanearnold at yahoo dot fr>}]
[moddesc {Tcl Math Library}]
[titledesc {Arbitrary precision floating-point numbers}]
[require Tcl [opt 8.4]]
[require math::bignum [opt 3.0]]
[require math::bigfloat [opt 1.2]]
[description]
The bigfloat package provides arbitrary precision floating-point math
capabilities to the Tcl language.
By convention, we will talk about the numbers treated in this library as :
[list_begin bullet]
[bullet]BigFloat for floating-point numbers of arbitrary length
[bullet]BigInt for arbitrary length signed integers (a.k.a. bignums)
[list_end]
BigFloats are internally represented at Tcl lists: this
package provides a set of procedures operating against
the internal representation in order to :
[list_begin bullet]
[bullet]
perform math operations on either BigFloats or BigInts.
[bullet]
convert BigFloats and BigInts from the internal representation to a string, and vice versa.
[list_end]
[section "INTRODUCTION"]
[list_begin definitions]
[call [cmd fromstr] [arg string] [opt [arg trailingZeros]]]
Converts [emph string] into a BigFloat, or a BigInt. Its precision
is at least the number of digits provided by [emph string].
If the [arg string] contains only digits and eventually a minus sign, it is considered as
an integer.
[nl]
[arg trailingZeros] - the number of zeros to append at the end of the floating-point number
to get more precision from the [emph string]. When applied on an integer, it throws an error.
[call [cmd fromstr] -base [arg radix] [arg string]]
Converts [emph string] representing an integer in the base [emph radix], to a BigInt.
[example_begin]
set x [lb]fromstr -1.000000[rb]
set y [lb]fromstr 2000e30[rb]
# x and y are BigFloats : the first string contained a dot, and the second an e sign
set m [lb]fromstr 1000[rb]
set n [lb]fromstr -39[rb]
# m and n are BigInts because the original string contained neither a dot nor an e sign
# negative BigInts are supported
set octalNumber [lb]fromstr -base 8 377[rb]
# the result is 377 in octal, so it is equal to 255
[example_end]
[nl]
The [emph string]'s last digit is considered by the procedure to be true at +/-1.
For instance, the Pi constant is irrational, so as you feed in the string "3.1415"
it may be considered as a number in the interval [lb]3.1414 , 3.1416[rb].
This is why we call such mathematics [emph "interval computations"].
For example, 0.1 belongs to the interval [lb]0.0, 0.2[rb],
and 1.00 to the interval [lb]0.99,1.01[rb].So, when you mean 1.0, you may have to write 1.000000 to get enough precision.
If you encounter problems with precision, I recommend you read [sectref PRECISION].
[nl]
For example :
[example_begin]
set x [lb]fromstr 1.0000000000[rb]
# the next line does the same, but smarter
set y [lb]fromstr 1. 10[rb]
# the next line set a BigInt equal to 1
set n [lb]fromstr 1[rb]
# the next line raises an error : a single argument is required
# for strings to BigInts conversions
set n [lb]fromstr 1 10[rb]
# the next line is correct
set n [lb]fromstr 1[lb]string repeat 0 10[rb][rb]
[example_end]
[call [cmd tostr] [arg number]]
Returns a string form of a BigFloat, in which all digits are exacts,
or the string form of a BigInt if [emph number] is not a BigFloat.
There is an issue with number equal to zero
(see section [sectref PRECISION]) : even if the precision about 0 is
more than one digit, it will always be displayed as the '[emph 0]' string.
[call [cmd fromdouble] [arg double] [opt [arg decimals]]]
Converts a double (a simple floating-point value) to a BigFloat, with
exactly [arg decimals] digits. Without the [arg decimals] argument,
it behaves like [emph fromstr].
[example_begin]
tostr [lb]fromstr 1.111 4[rb]
# returns : 1.111000 (3 zeroes)
tostr [lb]fromdouble 1.111 4[rb]
# returns : 1.111
[example_end]
[call [cmd todouble] [arg number]]
Returns a double, that may be used in [emph expr],
from a BigFloat.
[call [cmd isInt] [arg number]]
Returns 1 if [emph number] is a BigInt, 0 otherwise.
[call [cmd isFloat] [arg number]]
Returns 1 if [emph number] is a BigFloat, 0 otherwise.
[call [cmd int2float] [arg integer] [opt [arg decimals]]]
Converts a BigInt to a BigFloat with [emph decimals] trailing zeroes.
When converting back to string, one decimal is lost.
That is why the default, and minimal, number of [emph decimals] is 1.
[list_end]
[section "ARITHMETICS"]
[list_begin definitions]
[call [cmd add] [arg x] [arg y]]
[call [cmd sub] [arg x] [arg y]]
[call [cmd mul] [arg x] [arg y]]
Return the sum, difference and product of [emph x] by [emph y].
[arg x] - may be either a BigFloat or a BigInt
[arg y] - may be either a BigFloat or a BigInt
[call [cmd div] [arg x] [arg y]]
[call [cmd mod] [arg x] [arg y]]
Return the quotient and the rest of [emph x] divided by [emph y].
Each argument ([emph x] and [emph y]) can be either a BigFloat or a BigInt,
but you cannot divide a BigInt by a BigFloat
Divide by zero throws an error.
[call [cmd abs] [arg x]]
Returns the absolute value of [emph x]
[call [cmd opp] [arg x]]
Returns the opposite of [emph x]
[call [cmd pow] [arg x] [arg n]]
Returns [emph x] taken to the [emph n]th power.
It only works if [emph n] is a BigInt.
[emph x] might be a BigFloat or a BigInt.
[list_end]
[section COMPARISONS]
[list_begin definitions]
[call [cmd iszero] [arg x]]
Returns 1 if [emph x] is :
[list_begin bullet]
[bullet]a BigFloat close enough to zero to raise "divide by zero".
[bullet]a BigInt equal to 0.
[list_end]
[call [cmd equal] [arg x] [arg y]]
Returns 1 if [emph x] and [emph y] are equal, 0 elsewhere.
[call [cmd compare] [arg x] [arg y]]
Returns 0 if both BigFloat arguments are equal,
1 if [emph x] is greater than [emph y],
and -1 if [emph x] is lower than [emph y].
You might compare two BigFloats or two BigInts, but not a BigInt to a BigFloat.
[list_end]
[section ANALYSIS]
[list_begin definitions]
[call [cmd sqrt] [arg x]]
[call [cmd log] [arg x]]
[call [cmd exp] [arg x]]
[call [cmd cos] [arg x]]
[call [cmd sin] [arg x]]
[call [cmd tan] [arg x]]
[call [cmd cotan] [arg x]]
[call [cmd acos] [arg x]]
[call [cmd asin] [arg x]]
[call [cmd atan] [arg x]]
[call [cmd cosh] [arg x]]
[call [cmd sinh] [arg x]]
[call [cmd tanh] [arg x]]
The above functions return, respectively, the following :
square root, logarithm, exponential, cosine, sine,
tangent, cotangent, arc cosine, arc sine, arc tangent, hyperbolic
cosine, hyperbolic sine, hyperbolic tangent, of a BigFloat named [emph x].
[call [cmd pi] [arg n]]
Returns a BigFloat representing the Pi constant with [emph n] digits after the dot.
[emph n] may be either a simple string, or a BigInt.
[call [cmd rad2deg] [arg radians]]
[call [cmd deg2rad] [arg degrees]]
[arg radians] - angle expressed in radians (BigFloat)
[nl]
[arg degrees] - angle expressed in degrees (BigFloat)
[nl]
Convert an angle from radians to degrees, and [emph "vice versa"].
[list_end]
[section ROUNDING]
[list_begin definitions]
[call [cmd round] [arg x]]
[call [cmd ceil] [arg x]]
[call [cmd floor] [arg x]]
The above functions return the [emph x] BigFloat,
rounded like with the same mathematical function in [emph expr],
but returns a BigInt.
[list_end]
[section PRECISION]
Now you may ask this question : What precision am I going to get
after calling add, sub, mul or div?
When you set a number from the string representation, say
[example_begin]
set a [lb]fromstr 1.230[rb]
# $a is internally 1.230 +/- d.10^-3
# 'd' is a number in the [lb]1,2[lb] range
set a [lb]fromstr 1.000[rb]
# 'a' has a relative uncertainty in the range : [rb]0.1%,0.2%[rb]
# because 1*10^-3/1.000=0.1%, and 2*10^-3/1.000=0.2%
[example_end]
The uncertainty of the sum, or the difference, of two numbers, is the sum of the uncertainty
of each number.
[example_begin]
set a [lb]fromstr 1.230[rb]
set b [lb]fromstr 2.340[rb]
puts [lb]tostr [lb]add $a $b[rb][rb]
# the result is : 3.57 and the last digit of the sum is known with an uncertainty in the
# range [lb]2*10^-3,4*10^-3[lb]
[example_end]
But when operating a BigInt to a BigFloat (add, substract,etc.), the relative uncertainty
of the result is unchanged. So it is likely to keep integers as BigInt and not to
convert them to BigFloats.
[para]
For multiplication and division, the relative uncertainties of the product
or the quotient, is the sum of the relative uncertainties of the operands.
[para]
Take care about the fact that if a number contains 0 in its uncertainty interval,
it is always considered as if it was 0.
[example_begin]
set num [lb]fromstr 4.00[rb]
set denom [lb]fromstr 0.1[rb];# $denom is 0, because [lb]0.0,0.2[rb] contains 0
puts [lb]tostr $denom[rb];# prints "0" on the screen
set quotient [lb]div $num $denom[rb];# throws an error : divide by zero
set oppn [lb]opp $num[rb]
set oppd [lb]opp $denom[rb]
puts [lb]compare $num $oppn[rb];#prints 1
puts [lb]compare $denom $oppd[rb];#prints 0 !
[example_end]
[para]
For most analysis functions (cosinus, square root, logarithm, etc.), determining the precision
of the result is difficult.
It seems however that in many cases, the loss of precision in the result
is of one or two digits.
There are some exceptions : for example,
[example_begin]
tostr [lb]exp [lb]fromstr 100.0 10[rb][rb]
# returns : 2.688117142e+43 which has only 10 digits of precision, although the entry
# has 13 digits of precision.
[example_end]
[para]
How do conversions work with precision ?
[list_begin bullet]
[bullet] When a number is converted from string, the internal representation keep the uncertainty
as 1 to the exponent of the last digit.
[bullet] During computations, the uncertainty of each result is kept on two digits, eventually shifted and rounded when it is more than two digits long.
[bullet] When converting back to string, the digits that are printed are all digits except the two last digits,
because the last digits are subject to uncertainty.
[list_end]
Uncertainties are kept in the internal representation of the number ; it is likely to use
[emph tostr] only for outputting data (on the screen or in a file),
and never call [emph fromstr] with the result of [emph tostr].
It is better to always keep operands in their internal representation.
[section "NAMESPACES AND OTHER PACKAGES"]
You might import public commands with the following :
[example_begin]
namespace import ::math::bigfloat::*
[example_end]
If you matter much about avoiding names conflicts, I considere it should be resolved by the following :
[example_begin]
# the math::bignum package is required by the following statement
package require math::bigfloat
proc bigfloat {subcmd args} {
uplevel 1 [lb]concat ::math::bigfloat::$subcmd $args[rb]
}
set a [lb]bigfloat sub [lb]bigfloat fromstr 2.000[rb] [lb]bigfloat fromstr 0.530[rb][rb]
puts [lb]bigfloat tostr $a[rb]
[example_end]
[section "EXAMPLES"]
Guess what happens when you are doing some astronomy. Here is an example :
[example_begin]
# convert acurrate angles with a millisecond-rated accuracy
proc degree-angle {degrees minutes seconds milliseconds} {
set result [lb]fromstr 0[rb]
set div [lb]fromstr 1[rb]
foreach factor {1 1000 60 60} var [lb]list $milliseconds $seconds $minutes $degrees[rb] {
# we convert each entry var into milliseconds
set factor [lb]fromstr $factor[rb]
set div [lb]mul $div $factor[rb]
set result [lb]add $result [lb]mul [lb]fromstr $var[rb] $div[rb][rb]
}
return [lb]div [lb]int2float $result[rb] $div[rb]
}
# load the package
package require math::bigfloat
namespace import ::math::bigfloat::*
# work with angles : a standard formula for navigation (taking bearings)
set angle1 [lb]deg2rad [lb]degree-angle 20 30 40 0[rb][rb]
set angle2 [lb]deg2rad [lb]degree-angle 21 0 50 500[rb][rb]
set opposite3 [lb]deg2rad [lb]degree-angle 51 0 50 500[rb][rb]
set sinProduct [lb]mul [lb]sin $angle1[rb] [lb]sin $angle2[rb][rb]
set cosProduct [lb]mul [lb]cos $angle1[rb] [lb]cos $angle2[rb][rb]
set angle3 [lb]asin [lb]add [lb]mul $sinProduct [lb]cos $opposite3[rb][rb] $cosProduct[rb][rb]
puts "angle3 : [lb]tostr [lb]rad2deg $angle3[rb][rb]"
[example_end]
[keywords tcl multiprecision math floating-point]
[manpage_end]
|