8
$\begingroup$

Is there a simple way to enter decimal numbers such as 0.123 so that Mathematica interprets it as an exact rational number 123/1000?

$\endgroup$
9
  • 5
    $\begingroup$ Rationalize[0.123] $\endgroup$
    – Yi Wang
    Commented Feb 11, 2014 at 19:25
  • 3
    $\begingroup$ Rationalize does have limitations, though. $\endgroup$
    – Michael E2
    Commented Feb 11, 2014 at 19:51
  • $\begingroup$ @MichaelE2 Could you explain it a bit? $\endgroup$
    – Yi Wang
    Commented Feb 11, 2014 at 21:34
  • $\begingroup$ @YiWang Rationalize[0.333333], Rationalize[0.3333333333333], and the explanation in the docs: "Rationalize[x] yields x unchanged if there is no rational number close enough to x to satisfy the condition |p/q-x| < c/q^2, with c chosen to be 10^-4." $\endgroup$
    – Michael E2
    Commented Feb 11, 2014 at 21:51
  • 2
    $\begingroup$ @YiWang You're welcome! :) Even Rationalize[0.333333333, 0] does not do what the OP wants. $\endgroup$
    – Michael E2
    Commented Feb 11, 2014 at 21:58

2 Answers 2

6
$\begingroup$

No doubt this needs work to make robust:

 fract[s_String] := (ToExpression[StringReplace[s, "." -> ""]]/
     10^(StringLength[s] - First@First@StringPosition[s, "."]));

 $PreRead = If[Head[#] =!= Real, (
         # /. s_String :> StringReplace[s,
            a : ("." ~~ DigitCharacter ...) ~~ "*^" :> a <> " 10^"] /.
         s_String :> StringReplace[s, a : (
          (DigitCharacter .. ~~ "." ~~ DigitCharacter ...) |
          (DigitCharacter ... ~~ "." ~~ DigitCharacter ..)
             ) :> "fract[\"" <> a <> "\"]"] ), #, #] &


 (1.23 + .1*^4 x) /Sin[ .5 a ]

(123/100 + 1000 x) Csc[a/2]

Two known issues: this breaks if you use explicit precision backtic notation, or if your input contains floats within strings.

$\endgroup$
6
  • $\begingroup$ How about $Pre = # /. r_Real :> RuleCondition[Round[r, 10^-Ceiling@Precision@r]] & $\endgroup$ Commented Apr 15, 2014 at 16:06
  • $\begingroup$ The point is to work with the actual text entered to avoid some of the issues raised in the comments arising from conversion to/from machine precision. (As a practical matter those issues may not be important, and using $Pre like that is clearly cleaner and more robust ) $\endgroup$
    – george2079
    Commented Apr 15, 2014 at 16:57
  • 1
    $\begingroup$ May be a good idea to append /; StringMatchQ[s, RegularExpression["[+-]?[0-9]*\\.[0-9]+"]] to your fract: this will avoid all the possible breakage with unexpected formats of the string, returning unevaluated expression instead. $\endgroup$
    – Ruslan
    Commented Apr 9, 2017 at 9:06
  • $\begingroup$ @Ruslan: By "append to the end of fract" do you mean exactly this?: fract[s_String] := (ToExpression[StringReplace[s, "." -> ""]]/ 10^(StringLength[s] - First@First@StringPosition[s, "."]));/; StringMatchQ[s, RegularExpression["[+-]?[0-9]*\\.[0-9]+"]] $\endgroup$
    – theorist
    Commented Feb 26, 2018 at 7:43
  • 1
    $\begingroup$ @theorist not quite: insert it before the trailing semicolon — to make the pattern conditional $\endgroup$
    – Ruslan
    Commented Feb 26, 2018 at 7:57
1
$\begingroup$

Given the limitations described in the comments, a possibility is to use Ratiolize[x,0] in combination with SetPrecision or SetAccuracy. E.g.:

Rationalize[SetPrecision[0.33333, 5], 0]

1/3

While

Rationalize[SetAccuracy[0.3333, 5], 0] (* one less 3 *)

3332 / 9997

The point is to set Accuracy or Precision to the number of digits that would be normally entered to represent (conventionally) the desired rational as a floating point number.

$\endgroup$
5
  • 3
    $\begingroup$ I think the OP wants the outputs to be 33333/100000 and 3333/10000 respectively, but I think the simplest way to enter these numbers is 33333*^-5 and 3333*^-4, or as fractions. $\endgroup$
    – Michael E2
    Commented Feb 11, 2014 at 23:31
  • $\begingroup$ @MichaelE2 it's not really simplest if you want to be able to append digits (e.g. in a manual binary search): you have to carefully count the digits to make sure your order of magnitude isn't off and that you didn't to forget to change the exponent after you appended a new digit. $\endgroup$
    – Ruslan
    Commented Apr 9, 2017 at 8:41
  • $\begingroup$ @Ruslan If counting digits is a factor in a particular case, what's simpler than the second option, fractions, in which counting seems unnecessary? $\endgroup$
    – Michael E2
    Commented Apr 9, 2017 at 11:55
  • $\begingroup$ @MichaelE2 well, that's better, but inconvenient — it's always best to have to change one thing to get what you need. The simplest way would be to define a function, which would do it all for you, as fract in george2079's answer. $\endgroup$
    – Ruslan
    Commented Apr 9, 2017 at 13:51
  • $\begingroup$ @Ruslan I see what you mean. What seems simpler depends on context. E.g., how many conversions/entries do you have to do and how often. My personal, and admittedly parochial, experience is limited to infrequent and few conversions. Mostly nowadays they arise from converting parameters in SE questions to exact values, although Rationalize is usually sufficient. It hardly seems simpler to dredge up or write a function, when I can type the fraction in more quickly than I can find and type the function command. But it's different for even a moderate amount of data. $\endgroup$
    – Michael E2
    Commented Apr 9, 2017 at 14:22

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.