math::bigfloat(n) 1.2 math "Tcl Math Library"
math::bigfloat - Arbitrary precision floating-point numbers
TABLE OF CONTENTS
SYNOPSIS
DESCRIPTION
INTRODUCTION
ARITHMETICS
COMPARISONS
ANALYSIS
ROUNDING
PRECISION
NAMESPACES AND OTHER PACKAGES
EXAMPLES
KEYWORDS
COPYRIGHT
package require Tcl ?8.4?
package require math::bignum ?3.0?
package require math::bigfloat ?1.2?
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 :
- BigFloat for floating-point numbers of arbitrary length
- BigInt for arbitrary length signed integers (a.k.a. bignums)
BigFloats are internally represented at Tcl lists: this
package provides a set of procedures operating against
the internal representation in order to :
-
perform math operations on either BigFloats or BigInts.
-
convert BigFloats and BigInts from the internal representation to a string, and vice versa.
- fromstr string ?trailingZeros?
-
Converts string into a BigFloat, or a BigInt. Its precision
is at least the number of digits provided by string.
If the string contains only digits and eventually a minus sign, it is considered as
an integer.
trailingZeros - the number of zeros to append at the end of the floating-point number
to get more precision from the string. When applied on an integer, it throws an error.
- fromstr -base radix string
-
Converts string representing an integer in the base radix, to a BigInt.
|
set x [fromstr -1.000000]
set y [fromstr 2000e30]
# x and y are BigFloats : the first string contained a dot, and the second an e sign
set m [fromstr 1000]
set n [fromstr -39]
# m and n are BigInts because the original string contained neither a dot nor an e sign
# negative BigInts are supported
set octalNumber [fromstr -base 8 377]
# the result is 377 in octal, so it is equal to 255
|
The 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 [3.1414 , 3.1416].
This is why we call such mathematics interval computations.
For example, 0.1 belongs to the interval [0.0, 0.2],
and 1.00 to the interval [0.99,1.01].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 PRECISION.
For example :
|
set x [fromstr 1.0000000000]
# the next line does the same, but smarter
set y [fromstr 1. 10]
# the next line set a BigInt equal to 1
set n [fromstr 1]
# the next line raises an error : a single argument is required
# for strings to BigInts conversions
set n [fromstr 1 10]
# the next line is correct
set n [fromstr 1[string repeat 0 10]]
|
- tostr number
-
Returns a string form of a BigFloat, in which all digits are exacts,
or the string form of a BigInt if number is not a BigFloat.
There is an issue with number equal to zero
(see section PRECISION) : even if the precision about 0 is
more than one digit, it will always be displayed as the '0' string.
- fromdouble double ?decimals?
-
Converts a double (a simple floating-point value) to a BigFloat, with
exactly decimals digits. Without the decimals argument,
it behaves like fromstr.
|
tostr [fromstr 1.111 4]
# returns : 1.111000 (3 zeroes)
tostr [fromdouble 1.111 4]
# returns : 1.111
|
- todouble number
-
Returns a double, that may be used in expr,
from a BigFloat.
- isInt number
-
Returns 1 if number is a BigInt, 0 otherwise.
- isFloat number
-
Returns 1 if number is a BigFloat, 0 otherwise.
- int2float integer ?decimals?
-
Converts a BigInt to a BigFloat with decimals trailing zeroes.
When converting back to string, one decimal is lost.
That is why the default, and minimal, number of decimals is 1.
- add x y
-
- sub x y
-
- mul x y
-
Return the sum, difference and product of x by y.
x - may be either a BigFloat or a BigInt
y - may be either a BigFloat or a BigInt
- div x y
-
- mod x y
-
Return the quotient and the rest of x divided by y.
Each argument (x and y) can be either a BigFloat or a BigInt,
but you cannot divide a BigInt by a BigFloat
Divide by zero throws an error.
- abs x
-
Returns the absolute value of x
- opp x
-
Returns the opposite of x
- pow x n
-
Returns x taken to the nth power.
It only works if n is a BigInt.
x might be a BigFloat or a BigInt.
- iszero x
-
Returns 1 if x is :
- a BigFloat close enough to zero to raise "divide by zero".
- a BigInt equal to 0.
- equal x y
-
Returns 1 if x and y are equal, 0 elsewhere.
- compare x y
-
Returns 0 if both BigFloat arguments are equal,
1 if x is greater than y,
and -1 if x is lower than y.
You might compare two BigFloats or two BigInts, but not a BigInt to a BigFloat.
- sqrt x
-
- log x
-
- exp x
-
- cos x
-
- sin x
-
- tan x
-
- cotan x
-
- acos x
-
- asin x
-
- atan x
-
- cosh x
-
- sinh x
-
- tanh 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 x.
- pi n
-
Returns a BigFloat representing the Pi constant with n digits after the dot.
n may be either a simple string, or a BigInt.
- rad2deg radians
-
- deg2rad degrees
-
radians - angle expressed in radians (BigFloat)
degrees - angle expressed in degrees (BigFloat)
Convert an angle from radians to degrees, and vice versa.
- round x
-
- ceil x
-
- floor x
-
The above functions return the x BigFloat,
rounded like with the same mathematical function in expr,
but returns a BigInt.
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
|
set a [fromstr 1.230]
# $a is internally 1.230 +/- d.10^-3
# 'd' is a number in the [1,2[ range
set a [fromstr 1.000]
# 'a' has a relative uncertainty in the range : ]0.1%,0.2%]
# because 1*10^-3/1.000=0.1%, and 2*10^-3/1.000=0.2%
|
The uncertainty of the sum, or the difference, of two numbers, is the sum of the uncertainty
of each number.
|
set a [fromstr 1.230]
set b [fromstr 2.340]
puts [tostr [add $a $b]]
# the result is : 3.57 and the last digit of the sum is known with an uncertainty in the
# range [2*10^-3,4*10^-3[
|
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.
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 about the fact that if a number contains 0 in its uncertainty interval,
it is always considered as if it was 0.
|
set num [fromstr 4.00]
set denom [fromstr 0.1];# $denom is 0, because [0.0,0.2] contains 0
puts [tostr $denom];# prints "0" on the screen
set quotient [div $num $denom];# throws an error : divide by zero
set oppn [opp $num]
set oppd [opp $denom]
puts [compare $num $oppn];#prints 1
puts [compare $denom $oppd];#prints 0 !
|
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,
|
tostr [exp [fromstr 100.0 10]]
# returns : 2.688117142e+43 which has only 10 digits of precision, although the entry
# has 13 digits of precision.
|
How do conversions work with precision ?
- When a number is converted from string, the internal representation keep the uncertainty
as 1 to the exponent of the last digit.
- During computations, the uncertainty of each result is kept on two digits, eventually shifted and rounded when it is more than two digits long.
- 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.
Uncertainties are kept in the internal representation of the number ; it is likely to use
tostr only for outputting data (on the screen or in a file),
and never call fromstr with the result of tostr.
It is better to always keep operands in their internal representation.
You might import public commands with the following :
|
namespace import ::math::bigfloat::*
|
If you matter much about avoiding names conflicts, I considere it should be resolved by the following :
|
# the math::bignum package is required by the following statement
package require math::bigfloat
proc bigfloat {subcmd args} {
uplevel 1 [concat ::math::bigfloat::$subcmd $args]
}
set a [bigfloat sub [bigfloat fromstr 2.000] [bigfloat fromstr 0.530]]
puts [bigfloat tostr $a]
|
Guess what happens when you are doing some astronomy. Here is an example :
|
# convert acurrate angles with a millisecond-rated accuracy
proc degree-angle {degrees minutes seconds milliseconds} {
set result [fromstr 0]
set div [fromstr 1]
foreach factor {1 1000 60 60} var [list $milliseconds $seconds $minutes $degrees] {
# we convert each entry var into milliseconds
set factor [fromstr $factor]
set div [mul $div $factor]
set result [add $result [mul [fromstr $var] $div]]
}
return [div [int2float $result] $div]
}
# load the package
package require math::bigfloat
namespace import ::math::bigfloat::*
# work with angles : a standard formula for navigation (taking bearings)
set angle1 [deg2rad [degree-angle 20 30 40 0]]
set angle2 [deg2rad [degree-angle 21 0 50 500]]
set opposite3 [deg2rad [degree-angle 51 0 50 500]]
set sinProduct [mul [sin $angle1] [sin $angle2]]
set cosProduct [mul [cos $angle1] [cos $angle2]]
set angle3 [asin [add [mul $sinProduct [cos $opposite3]] $cosProduct]]
puts "angle3 : [tostr [rad2deg $angle3]]"
|
floating-point, math, multiprecision, tcl
Copyright © 2004-2005 Stephane Arnold <stephanearnold at yahoo dot fr>