How to get exact Rationalize of a decimal number?
You can use SetPrecision
to find a more precise result.
r0 = 0.97646105481464028;
r1 = Rationalize[r0]
r2 = SetPrecision[r0, Infinity]
8795179285210031/9007199254740992
r2 - r0
0.
If you increase the Precision
of your input, you can get a rational number that is closer to 0.97646105481464028.
Precision@r0
MachinePrecision
r0 = 0.97646105481464028`100;
Precision@r0
100.
r3 = SetPrecision[r0, Infinity]
17086121198925650302678220692982191831883180533886836969508025507253230621682061409501393058711047971/ 17498005798264095394980017816940970922825355447145699491406164851279623993595007385788105416184430592
Comparing with your Maple result:
maple = 24411526370366007/25000000000000000;
N[maple, 17]
N[r2, 17]
N[r3, 17]
0.97646105481464028
0.97646105481464029
0.97646105481464028
When you simply input 0.97646105481464028
, you do not get this number internally:
0.97646105481464028 // FullForm
0.9764610548146403`
Hence you can't expect any internal function to return exactly 97646105481464028/100000000000000000
from the above numeric input.
In order to preserve exact decimal representation of the original number, you need to specify explicit Precision
or Accuracy
(which do the same in this particular case):
RealDigits[0.97646105481464028`17]
RealDigits[0.97646105481464028``17]
{{9, 7, 6, 4, 6, 1, 0, 5, 4, 8, 1, 4, 6, 4, 0, 2, 8}, 0} {{9, 7, 6, 4, 6, 1, 0, 5, 4, 8, 1, 4, 6, 4, 0, 2, 8}, 0}
FromDigits[%]
% - 97646105481464028/100000000000000000
24411526370366007/25000000000000000 0
Note that RealDigits
drops the sign, hence in the general case you have to multiply the output of FromDigits
by Sign
:
Sign[#]*FromDigits[RealDigits[#]] &@-0.97646105481464028`17
-(24411526370366007/25000000000000000)
Question: How to get exact
Rationalize
for the above from Mathematica?
It depends on what do you mean under the "exact" rational representation of an inexact number. One approach via RealDigits
I have given above. Rationalize
and SetPrecision
implement other approaches:
Rationalize[x,0]
gives a rational that is equivalent tox
up to the precision ofx
SetPrecision[x,∞]
gets a rational directly from the bitwise representation ofx
In the comment Hurkyl gives a concise explanation why Rationalize
doesn't give an "exact" representation by default:
Incidentally, the main application of
Rationalize
is when you've numerically computed a rational number (or what you hope to be a rational number), and you want to obtain the true rational value from its numerical approximation. Exactly representing the specific floating-point approximation is the wrong answer to this problem.
I've found, empirically, that I can ensure Rationalize[ ] provides an exact rational conversion of whatever decimal I enter (call it "num") if I evaluate Rationalize[num`z, 0] where:
$z \geq 2*\text{Length@RealDigits[num][[1]]} + 1$
E.g.,
Length@RealDigits[0.97646105481464028][[1]]
==>16
so:
Rationalize[0.97646105481464028`33, 0]
==>24411526370366007/25000000000000000
24411526370366007/25000000000000000==97646105481464028/100000000000000000
==>True
but
Rationalize[0.39984759300000068`32, 0]
==>5594893179322259/5729765822953714
5594893179322259/5729765822953714==97646105481464028/100000000000000000
==>False
I'd like to understand why that's the cutoff*, so I'll be posting my own question on that soon. [*That's the general cutoff; there are some decimals that are exactly converted with a lower value of z, but I've not found any that require a higher value for z.]
Alternately, you can also achieve an exact rational conversion using Round[num`y, 10^-y], where (again, empricially), I've found that:
$y \geq \text{Length@RealDigits[num][[1]]} + 1$
Thus:
Round[0.97646105481464028`17, 10^-17]
==>24411526370366007/25000000000000000
but
Round[0.39984759300000068`16, 10^-16]
==>5594893179322259/5729765822953714
Finally, one way to understand why SetPrecision[num`z, Infinity] won't generally give an exact rational conversion of the decimal you enter is that SetPrecision[ ] is restricted to converting "num" to that subset of rational base-10 numbers that can be represented in binary with a finite number of digits; it then pads that binary with an infinite number of zeros. And, while there are exceptions (e.g., 0.5), decimals typically can't be exactly represented with a finite binary.
Thus:
RealDigits[SetPrecision[0.97646105481464028`33, Infinity], 2, 300]
==>{1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1,
0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,
1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0}
and
Take[RealDigits[SetPrecision[0.97646105481464028`33, Infinity], 2,
10^9][[1]], -100]
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0}
But:
RealDigits[Rationalize[0.97646105481464028`33, 0], 2, 300]
==>{1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1,
0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1,
1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,
1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,
0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0,
1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0,
1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0,
0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1,
1}
and
Take[RealDigits[Rationalize[0.97646105481464028`33, 0], 2,
10^9][[1]], -100]
{1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1,
1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0,
0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1,
1, 0, 1, 1, 1, 0, 0, 0}
You might also want to take a look at the answer by george2079 here: Enter exact rational numbers easily with decimal notation
Note also that the part of the documentation you quoted with p,q,c
applies only to the single-argument Rationalize[x]
forms, as noted by sn6uv here: Rationalize error. For the dual-argument forms, Rationalize[x, dx]
(excepting where dx = 0, which is what I was using above), Daniel Lichtblau, at that same link, says: "I'd say the documentation could be worded better for the 2-argument case of Rationalize. There is an interplay between denominator of result, epsilon, and size of residual. If you take dx as replacing the default epsilon then I think the correct claim might be to the effect: ratPi = Rationalize[N[Pi], eps]; Abs[N[Pi] - ratPi] < N[eps]/Denominator[ratPi]^2.
"