numeric::rationalize --
approximate a floating point number by a rational number
Introductionnumeric::rationalize(object, ..) replaces
all floating point numbers in object by rational
numbers.
Call(s)numeric::rationalize(object <, mode> <,
digits>)
Parametersobject |
- | an arbitrary MuPAD object |
Options |
- | 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. |
ReturnsIf 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
Side
EffectsThe function is sensitive to the environment variable DIGITS.
Details
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.
Option:
digitsWith 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.
Option: Exactf=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.
Option: Minimizedigits.
Option: Restorer 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!
Example
1numeric::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 / } --
Example
2We 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
Example
3We 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
Example
4We 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:
Example
5The 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]}
Backgroundsharelib::rational