From 07fc041d7bc0793318dd31ebef6ab2da9bcb3fe2 Mon Sep 17 00:00:00 2001 From: Omar Rizwan Date: Mon, 5 Dec 2022 02:14:51 -0500 Subject: Vendor tcllib linear algebra --- vendor/math/bigfloat.man | 433 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 vendor/math/bigfloat.man (limited to 'vendor/math/bigfloat.man') diff --git a/vendor/math/bigfloat.man b/vendor/math/bigfloat.man new file mode 100644 index 00000000..34fe0e21 --- /dev/null +++ b/vendor/math/bigfloat.man @@ -0,0 +1,433 @@ +[vset VERSION 2.0.4] +[manpage_begin math::bigfloat n [vset VERSION]] +[keywords computations] +[keywords floating-point] +[keywords interval] +[keywords math] +[keywords multiprecision] +[keywords tcl] +[copyright {2004-2008, by Stephane Arnold }] +[moddesc {Tcl Math Library}] +[titledesc {Arbitrary precision floating-point numbers}] +[category Mathematics] +[require Tcl 8.5] +[require math::bigfloat [opt [vset VERSION]]] + +[description] + +The bigfloat package provides arbitrary precision floating-point math +capabilities to the Tcl language. It is designed to work with Tcl 8.5, +but for Tcl 8.4 is provided an earlier version of this package. +See [sectref "WHAT ABOUT TCL 8.4 ?"] for more explanations. +By convention, we will talk about the numbers treated in this library as : +[list_begin itemized] +[item]BigFloat for floating-point numbers of arbitrary length. +[item]integers for arbitrary length signed integers, just as basic integers since Tcl 8.5. +[list_end] +Each BigFloat is an interval, namely [lb][emph "m-d, m+d"][rb], +where [emph m] is the mantissa and [emph d] the uncertainty, representing the +limitation of that number's precision. +This is why we call such mathematics [emph "interval computations"]. +Just take an example in physics : when you measure a temperature, not all +digits you read are [emph significant]. Sometimes you just cannot trust all digits - not to mention if doubles (f.p. numbers) can handle all these digits. +BigFloat can handle this problem - trusting the digits you get - plus the ability to store numbers with an arbitrary precision. + +BigFloats are internally represented at Tcl lists: this +package provides a set of procedures operating against +the internal representation in order to : +[list_begin itemized] +[item] +perform math operations on BigFloats and (optionnaly) with integers. + +[item] +convert BigFloats from their internal representations to strings, and vice versa. + +[list_end] + +[section "INTRODUCTION"] +[list_begin definitions] + +[call [cmd fromstr] [arg number] [opt [arg trailingZeros]]] +Converts [emph number] into a BigFloat. Its precision +is at least the number of digits provided by [emph number]. +If the [arg number] contains only digits and eventually a minus sign, it is considered as +an integer. Subsequently, no conversion is done at all. +[para] +[arg trailingZeros] - the number of zeros to append at the end of the floating-point number +to get more precision. It cannot be applied to an integer. + +[example_begin] +# x and y are BigFloats : the first string contained a dot, and the second an e sign +set x [lb]fromstr -1.000000[rb] +set y [lb]fromstr 2000e30[rb] +# let's see how we get integers +set t 20000000000000 +# the old way (package 1.2) is still supported for backwards compatibility : +set m [lb]fromstr 10000000000[rb] +# but we do not need fromstr for integers anymore +set n -39 +# t, m and n are integers +[example_end] +[para] +The [emph number]'s last digit is considered by the procedure to be true at +/-1, +For example, 1.00 is the interval [lb]0.99, 1.01[rb], +and 0.43 the interval [lb]0.42, 0.44[rb]. +The Pi constant may be approximated by the number "3.1415". +This string could be considered as the interval [lb]3.1414 , 3.1416[rb] by [cmd fromstr]. +So, when you mean 1.0 as a double, you may have to write 1.000000 to get enough precision. +To learn more about this subject, see [sectref PRECISION]. +[para] +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] +[example_end] + +[call [cmd tostr] [opt [option -nosci]] [arg number]] +Returns a string form of a BigFloat, in which all digits are exacts. +[emph "All exact digits"] means a rounding may occur, for example to zero, +if the uncertainty interval does not clearly show the true digits. +[emph number] may be an integer, causing the command to return exactly the input argument. +With the [option -nosci] option, the number returned is never shown in scientific +notation, i.e. not like '3.4523e+5' but like '345230.'. +[example_begin] +puts [lb]tostr [lb]fromstr 0.99999[rb][rb] ;# 1.0000 +puts [lb]tostr [lb]fromstr 1.00001[rb][rb] ;# 1.0000 +puts [lb]tostr [lb]fromstr 0.002[rb][rb] ;# 0.e-2 +[example_end] +See [sectref PRECISION] for that matter. + +See also [cmd iszero] for how to detect zeros, which is useful when performing a division. + +[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 [cmd fromstr]. +Here, the only important feature you might care of is the ability +to create BigFloats with a fixed number of [arg decimals]. + +[example_begin] +tostr [lb]fromstr 1.111 4[rb] +# returns : 1.111000 (3 zeros) +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 an integer, 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 an integer to a BigFloat with [emph decimals] trailing zeros. +The default, and minimal, number of [emph decimals] is 1. +When converting back to string, one decimal is lost: +[example_begin] +set n 10 +set x [lb]int2float $n[rb]; # like fromstr 10.0 +puts [lb]tostr $x[rb]; # prints "10." +set x [lb]int2float $n 3[rb]; # like fromstr 10.000 +puts [lb]tostr $x[rb]; # prints "10.00" +[example_end] + +[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 an integer +[arg y] - may be either a BigFloat or an integer +When both are integers, these commands behave like [cmd expr]. + +[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 an integer, +but you cannot divide an integer 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 an integer. +[emph x] might be a BigFloat or an integer. + +[list_end] + +[section COMPARISONS] +[list_begin definitions] +[call [cmd iszero] [arg x]] + +Returns 1 if [emph x] is : +[list_begin itemized] +[item]a BigFloat close enough to zero to raise "divide by zero". +[item]the integer 0. +[list_end] +See here how numbers that are close to zero are converted to strings: +[example_begin] +tostr [lb]fromstr 0.001[rb] ; # -> 0.e-2 +tostr [lb]fromstr 0.000000[rb] ; # -> 0.e-5 +tostr [lb]fromstr -0.000001[rb] ; # -> 0.e-5 +tostr [lb]fromstr 0.0[rb] ; # -> 0. +tostr [lb]fromstr 0.002[rb] ; # -> 0.e-2 + +set a [lb]fromstr 0.002[rb] ; # uncertainty interval : 0.001, 0.003 +tostr $a ; # 0.e-2 +iszero $a ; # false + +set a [lb]fromstr 0.001[rb] ; # uncertainty interval : 0.000, 0.002 +tostr $a ; # 0.e-2 +iszero $a ; # true +[example_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 would not be able to compare an integer to a BigFloat : +the operands should be both BigFloats, or both integers. + +[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] is a positive integer. + +[call [cmd rad2deg] [arg radians]] +[call [cmd deg2rad] [arg degrees]] +[arg radians] - angle expressed in radians (BigFloat) +[para] +[arg degrees] - angle expressed in degrees (BigFloat) +[para] +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], +and returns it as an integer. +[list_end] + +[section PRECISION] + +How do conversions work with precision ? + +[list_begin itemized] +[item] When a BigFloat is converted from string, the internal representation +holds its uncertainty as 1 at the level of the last digit. +[item] During computations, the uncertainty of each result +is internally computed the closest to the reality, thus saving the memory used. +[item] When converting back to string, the digits that are printed +are not subject to uncertainty. However, some rounding is done, as not doing so +causes severe problems. +[list_end] +Uncertainties are kept in the internal representation of the number ; +it is recommended to use [cmd tostr] only for outputting data (on the screen or in a file), +and NEVER call [cmd fromstr] with the result of [cmd tostr]. +It is better to always keep operands in their internal representation. +Due to the internals of this library, the uncertainty interval may be slightly +wider than expected, but this should not cause false digits. +[para] + +Now you may ask this question : What precision am I going to get +after calling add, sub, mul or div? +First you set a number from the string representation and, +by the way, its uncertainty is set: +[example_begin] +set a [lb]fromstr 1.230[rb] +# $a belongs to [lb]1.229, 1.231[rb] +set a [lb]fromstr 1.000[rb] +# $a belongs to [lb]0.999, 1.001[rb] +# $a has a relative uncertainty of 0.1% : 0.001(the uncertainty)/1.000(the medium value) +[example_end] +The uncertainty of the sum, or the difference, of two numbers, is the sum +of their respective uncertainties. + +[example_begin] +set a [lb]fromstr 1.230[rb] +set b [lb]fromstr 2.340[rb] +set sum [lb]add $a $b[rb][rb] +# the result is : [lb]3.568, 3.572[rb] (the last digit is known with an uncertainty of 2) +tostr $sum ; # 3.57 +[example_end] +But when, for example, we add or substract an integer to a BigFloat, +the relative uncertainty of the result is unchanged. So it is desirable +not to convert integers to BigFloats: + +[example_begin] +set a [lb]fromstr 0.999999999[rb] +# now something dangerous +set b [lb]fromstr 2.000[rb] +# the result has only 3 digits +tostr [lb]add $a $b[rb] + +# how to keep precision at its maximum +puts [lb]tostr [lb]add $a 2[rb][rb] +[example_end] +[para] + +For multiplication and division, the relative uncertainties of the product +or the quotient, is the sum of the relative uncertainties of the operands. +Take care of division by zero : check each divider with [cmd iszero]. + +[example_begin] +set num [lb]fromstr 4.00[rb] +set denom [lb]fromstr 0.01[rb] + +puts [lb]iszero $denom[rb];# true +set quotient [lb]div $num $denom[rb];# error : divide by zero + +# opposites of our operands +puts [lb]compare $num [lb]opp $num[rb][rb]; # 1 +puts [lb]compare $denom [lb]opp $denom[rb][rb]; # 0 !!! +# No suprise ! 0 and its opposite are the same... +[example_end] + +Effects of the precision of a number considered equal to zero +to the cos function: +[example_begin] +puts [lb]tostr [lb]cos [lb]fromstr 0. 10[rb][rb][rb]; # -> 1.000000000 +puts [lb]tostr [lb]cos [lb]fromstr 0. 5[rb][rb][rb]; # -> 1.0000 +puts [lb]tostr [lb]cos [lb]fromstr 0e-10[rb][rb][rb]; # -> 1.000000000 +puts [lb]tostr [lb]cos [lb]fromstr 1e-10[rb][rb][rb]; # -> 1.000000000 +[example_end] + +BigFloats with different internal representations may be converted +to the same string. + +[para] + +For most analysis functions (cosine, 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 14 digits of precision. +[example_end] + +[section "WHAT ABOUT TCL 8.4 ?"] +If your setup do not provide Tcl 8.5 but supports 8.4, the package can still be loaded, +switching back to [emph math::bigfloat] 1.2. Indeed, an important function introduced in Tcl 8.5 +is required - the ability to handle bignums, that we can do with [cmd expr]. +Before 8.5, this ability was provided by several packages, +including the pure-Tcl [emph math::bignum] package provided by [emph tcllib]. +In this case, all you need to know, is that arguments to the commands explained here, +are expected to be in their internal representation. +So even with integers, you will need to call [cmd fromstr] +and [cmd tostr] in order to convert them between string and internal representations. +[example_begin] +# +# with Tcl 8.5 +# ============ +set a [lb]pi 20[rb] +# round returns an integer and 'everything is a string' applies to integers +# whatever big they are +puts [lb]round [lb]mul $a 10000000000[rb][rb] +# +# the same with Tcl 8.4 +# ===================== +set a [lb]pi 20[rb] +# bignums (arbitrary length integers) need a conversion hook +set b [lb]fromstr 10000000000[rb] +# round returns a bignum: +# before printing it, we need to convert it with 'tostr' +puts [lb]tostr [lb]round [lb]mul $a $b[rb][rb][rb] +[example_end] +[section "NAMESPACES AND OTHER PACKAGES"] +We have not yet discussed about namespaces +because we assumed that you had imported public commands into the global namespace, +like this: +[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] +package require math::bigfloat +# beware: namespace ensembles are not available in Tcl 8.4 +namespace eval ::math::bigfloat {namespace ensemble create -command ::bigfloat} +# from now, the bigfloat command takes as subcommands all original math::bigfloat::* commands +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 0 + set div 1 + foreach factor {1 1000 60 60} var [lb]list $milliseconds $seconds $minutes $degrees[rb] { + # we convert each entry var into milliseconds + set div [lb]expr {$div*$factor}[rb] + incr result [lb]expr {$var*$div}[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] + +[vset CATEGORY {math :: bignum :: float}] +[include ../common-text/feedback.inc] +[manpage_end] -- cgit v1.2.3