6
$\begingroup$

This is on Mathematica 11.1 on Windows 7.

I have this value 0.97646105481464028 which I'd like to get exact rational for it. I have thought that every terminating decimal number as the above could always be converted to an exact rational number? One direct way would be to write it as 97646105481464028/100000000000000000?

My question is, how to make Mathematica Rationalize the above to an exact rational? This is what I tried:

r0=0.97646105481464028;
r1=Rationalize[r0]

which gives

0.9764610548146403

Then I tried

r2=Rationalize[r0,0]

which gives

50543748/51762175

But the above is not an exact, because

r2 - r0

gives

-1.1102230246251565*10^-16

I read the help, and even clicked on the new nice big thumb image for the details, but I do not understand what Mathematica means when it says

Mathematica graphics

I do not understand what the p,q,c come from and how to use them.

In Maple I can do this:

  r0:=0.97646105481464028:
  r2:=convert(r0, rational,'exact');

Mathematica graphics

Maple help, FYI, on this option is the following:

If the third argument digits is the name 'exact' then an exact conversion of float to a rational will be performed; thus Float(f, e) becomes simply f*10^e. Note that exact conversion executes much more quickly than the more sophisticated conversion.

Then I copied the above to Mathematica to check:

r0=0.97646105481464028;
maple=24411526370366007/25000000000000000;
r0-maple

gives

0.`

Question: How to get exact Rationalize for the above from Mathematica?

$\endgroup$
5
  • $\begingroup$ You can check the Properties & Relations section for an explanation for the meaning of p,q,c. $\endgroup$
    – Karsten7
    Apr 2, 2017 at 3:21
  • 1
    $\begingroup$ A related question. $\endgroup$ Apr 2, 2017 at 5:55
  • $\begingroup$ @J.M. You do not feel that is a duplicate? $\endgroup$
    – Mr.Wizard
    Apr 2, 2017 at 6:37
  • 3
    $\begingroup$ 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. $\endgroup$
    – user5147
    Apr 2, 2017 at 8:27
  • $\begingroup$ @Mr. Wizard, what Hurkyl said, which is why it's only a comment. $\endgroup$ Apr 2, 2017 at 9:45

5 Answers 5

10
$\begingroup$

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

$\endgroup$
2
  • $\begingroup$ The output from SetAccuracy in your answer is wrong. I get identical results from SetAccuracy[r0, Infinity] and SetPrecision[r0, Infinity] for r0 = 0.97646105481464028; with Mathematica 11.1.0. Also please see my answer below. $\endgroup$ Apr 2, 2017 at 6:22
  • $\begingroup$ @AlexeyPopkov Thanks for pointing that out. You are correct my r0 had another, higher precision value. $\endgroup$
    – Karsten7
    Apr 2, 2017 at 7:29
7
$\begingroup$

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 to x up to the precision of x

SetPrecision[x,∞] gets a rational directly from the bitwise representation of x


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.

$\endgroup$
4
$\begingroup$

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."

$\endgroup$
3
$\begingroup$

You can find fractions with smaller numerators and denominators by using continued fractions.

r0 = 0.9764610548146402800000000000000;

s = ContinuedFraction[r0, 20]

(*{0, 1, 41, 2, 14, 41, 2, 21, 2, 10, 1, 6, 6, 1, 2, 6, 1, 5, 3, 2}*)

FromContinuedFraction[s]

(*2258911026868/2313365203589*)

0.97646105481464028 - 2258911026868/2313365203589

{*0*)

As J.M. points out below, we do not have to guess for the magical number 20.

Convergents[r0]

does everything for us.

$\endgroup$
2
  • 2
    $\begingroup$ Have you seen Convergents[] already? $\endgroup$ Apr 2, 2017 at 5:09
  • $\begingroup$ Hi; J.M. yes I know about that but I did not think of using it. I was so excited about finding a smaller fraction. Thanks! $\endgroup$
    – bobbym
    Apr 2, 2017 at 5:14
2
$\begingroup$

This is related to the response by @AlexeyPopkov. The idea is to use the computed base 10 digits to construct a base 10 rational approximation.

baseTenRationalize[num_Real] := With[
  {rd = RealDigits[num]}, {denom = 10^(Length[rd[[1]]] - rd[[2]])},
  Round[denom*num]/denom
  ]

A slight modification of the example in question:

baseTenRationalize[9.7646105481464028]

(* Out[60]= 4882305274073201/500000000000000 *)

This does not quite capture the last digit or so of the base 10 input. That's because we are losing a bit or so, literally, in going from decimal input to binary internal representation and back to decimal. One can force higher precision by using bignum input.

baseTenRationalize[9.7646105481464028`17]

(* Out[61]= 24411526370366007/2500000000000000 *)
$\endgroup$
6
  • $\begingroup$ What are the advantages of this approach as compared to FromDigits[RealDigits[9.7646105481464028`17]]? $\endgroup$ Apr 2, 2017 at 16:16
  • $\begingroup$ @AlexeyPopkov Probably none. What I showed might just be a longer version thereof. $\endgroup$ Apr 2, 2017 at 16:29
  • $\begingroup$ 17 digit long real numbers like 0.97646105481464028 seem to be the edge case, where one loses the last digit. From my experience, every longer input gets converted to an arbitrary precision number correctly and for every shorter input machine-precision is enough. In other words: Shouldn't Mathematica convert the input 0.97646105481464028 to an arbitrary precision number with Accuracy 17 as it converts the input 0.976461054814640280 to a number with Accuracy 18? $\endgroup$
    – Karsten7
    Apr 2, 2017 at 18:57
  • 2
    $\begingroup$ But the machine precision number input would be 0.97646105481464028` according to the documentation. Also I was not just talking about input to Mathematica, but also input to RealDigits. For example r0 = 0.12345678901234567; r1 = 0.12345678901234568; have different FullForms, but the same RealDigits. $\endgroup$
    – Karsten7
    Apr 2, 2017 at 23:39
  • 1
    $\begingroup$ @Karsten7 I may be mistaken but I think one problem is that often machine numbers are presented with 17 (as opposed to 16) digits present. I confess that offhand I do not know what is the reason for Mathematica interpreting 17 digit decimals as machine numbers, but it might be related to this. $\endgroup$ Apr 3, 2017 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.