numeric::rationalize
--
approximate a floating point number by a rational numbernumeric::rationalize
(object, ..)
replaces
all floating point numbers in object
by rational
numbers.
numeric::rationalize(object <, mode> <,
digits>)
object |
- | an arbitrary MuPAD object |
|
- | either Exact, or Minimize, or Restore. This controls the strategy for approximating floating point numbers by rational numbers. |
|
- | a positive integer (the number of decimal digits) not
bigger than the environment variable DIGITS . It determines the precision
of the rational approximation. |
If the argument is an object of some kernel domain, then it is returned with all floating point operands replaced by rational numbers. An object of some library domain is returned unchanged.
object
The function is sensitive to the environment variable DIGITS
.
domtype(extop(object,0))=DOM_DOMAIN
,
is returned unchanged. For all other objects
numeric::rationalize
is applied recursively to all
operands. Objects of library domains can be rationalized, if the domain
has an appropriate map
method. Cf. example 5.digits
With the options Exact and Minimize the guaranteed precision is
eps=10^(-digits
). With Restore the guaranteed precision is only
eps=10^(-digits
/2).
digits=DIGITS
.DIGITS
: an error occurs for
digits>DIGITS
.f=sign(f)*mantissa*10^(exponent)with integer exponent and 1.0<= mantissa<10.0. With the option Exact the float mantissa is replaced by the rational approximation
round(mantissa*10^digits)/10^digits.This guarantees a relative precision of
digits
significant
decimals of the rational approximation.numeric::rationalize
.digits
.r
the float division f =
1/float(r)
introduces additional round-off, which the Restore algorithm tries to eliminate:
numeric::rationalize
(f, Restore) = 1/r
. This
strategy, however, is purely heuristic and will not succeed, when
significant round-off is caused by arithmetical float operations!The guaranteed precision of the rational
approximation is only digits/2
!
numeric::rationalize
is applied to each
operand of a composite object:
>> numeric::rationalize(0.2*a+b^(0.7*I))
a 7/10 I - + b 5
>> numeric::rationalize([{poly(0.2*x, [x]), sin(7.2*PI) + 1.0*I}, exp(3 + ln(2.0*x))])
-- { / 36 PI \ } -- | { poly(1/5 x, [x]), sin| ----- | + I }, exp(ln(2 x) + 3) | -- { \ 5 / } --
We demonstrate the default strategy Exact:
>> numeric::rationalize(12.3 + 0.5*I), numeric::rationalize(0.33333), numeric::rationalize(1/3.0)
123/10 + 1/2 I, 33333/100000, 33333333333/100000000000
>> numeric::rationalize(10^12/13.0), numeric::rationalize(10^(-12)/13.0)
76923076923, 76923076923/1000000000000000000000000
We reduce the precision of the approximation to 5 digits:
>> numeric::rationalize(10^12/13.0, 5), numeric::rationalize(10^(-12)/13.0, 5)
76923100000, 769231/10000000000000000000
We demonstrate the strategy Minimize for minimizing the complexity of the resulting rational number:
>> numeric::rationalize(1/13.0, 5), numeric::rationalize(1/13.0, Minimize, 5), numeric::rationalize(0.333331, 5), numeric::rationalize(0.333331, Minimize, 5), numeric::rationalize(14.285, 5), numeric::rationalize(14.2857, Minimize, 5), numeric::rationalize(1234.1/56789.2), numeric::rationalize(1234.1/56789.2, Minimize)
769231/10000000, 1/13, 333331/1000000, 1/3, 2857/200, 100/7, 21731244673/1000000000000, 12341/567892
We compute rational approximations of PI with various precisions:
>> numeric::rationalize(float(PI), Minimize, i) $ i = 1..10
3, 22/7, 22/7, 355/113, 355/113, 355/113, 355/113, 102573/32650, 104348/33215, 208341/66317
We demonstrate the strategy Restore for restoring rational numbers after elementary float operations. In many cases also the Minimize strategy restores:
>> numeric::rationalize(1/7.3, Exact), numeric::rationalize(1/7.3, Minimize), numeric::rationalize(1/7.3, Restore)
13698630137/100000000000, 10/73, 10/73
However, using Restore improves the chances of recovering from round-off effects:
>> numeric::rationalize(10^12/13.0, Minimize), numeric::rationalize(10^12/13.0, Restore)
76923076923, 1000000000000/13
>> numeric::rationalize(123.456/12.34567, Minimize), numeric::rationalize(123.456/12.34567, Restore)
529097/52910, 12345600/1234567
In some cases Restore manages to recover from round-off error propagation in composite arithmetical operations:
>> x := 125/12.34567: y := 123/12.34567: z := (x^2 - y^2)/(x + y)
0.1620001183
>> numeric::rationalize(z, Minimize), numeric::rationalize(z, Restore)
35612/219827, 200000/1234567
The result with Restore corresponds to exact arithmetic:
>> rx := numeric::rationalize(x, Restore):
>> ry := numeric::rationalize(y, Restore):
>> (rx^2 - ry^2)/(rx + ry)
200000/1234567
Note that an approximation with Restore may have a reduced precision of only
digits/2
:
>> x := 1.0 + 1/10^6:
>> numeric::rationalize(x, Exact), numeric::rationalize(x, Restore)
1000001/1000000, 1
>> delete x, y, z, rx, ry:
The floats inside objects of library domains are not
rationalized directly. However, for most domains the corresponding
map
method can forward numeric::rationalize
to the operands:
>> Dom::Multiset(0.2, 0.2, 1/5, 0.3)
{[0.3, 1], [0.2, 2], [1/5, 1]}
>> numeric::rationalize(%), map(%, numeric::rationalize, Restore)
{[0.3, 1], [0.2, 2], [1/5, 1]}, {[1/5, 3], [3/10, 1]}
sharelib::rational