I would like to know a good way of checking if a number x is a rational (two integers n,m exist so that x=n/m) in python.
In Mathematica, this is done by the function Rationalize[6.75]
: 27/4
I assume this question has an answer for a given accuracy. Is there a common algorithm of obtaining these two integers?
The problem with real numbers in programming languages is that they are usually defined as functions returning a finite representation given an accuracy (eg. a function which takes n as an argument and returns a floating point number within 2^-n accuracy).
You can definitely turn a rational/integer into a real, but even comparing reals for equality is undecidable (it is essentially the halting problem).
You cannot tell whether a real number x is rational: even in mathematics, it is usually difficult, since you have to find p and q such that x = p/q, and this is often non constructive.
However, given an accuracy window, you can find the "best" rational approximation for this accuracy using for instance continuous fraction expansion. I believe that is essentially what mathematica does. But in your exemple, 6.75 is already rational. Try with Pi instead.
May be this will be interesting to you: Best rational approximation
Any number with a finite decimal expansion is a rational number. You could always solve for instance
by saying that it corresponds to
So since floats and doubles have finite precision they're all rationals.
The nature of floating-point numbers means that it makes no sense to check if a floating-point number is rational, since all floating-point numbers are really fractions of the form n / 2e. However, you might well want to know whether there is a simple fraction (one with a small denominator rather than a big power of 2) that closely approximates a given floating-point number.
Donald Knuth discusses this latter problem in The Art of Computer Programming volume II. See the answer to exercise 4.53-39. The idea is to search for the fraction with the lowest denominator within a range, by expanding the endpoints of the range as continued fractions so long as their coefficients are equal, and then when they differ, take the simplest value between them. Here's a fairly straightforward implementation in Python:
And here are some results:
As you noted any floating point number can be converted to a rational number by moving the decimal point and dividing by the appropriate power of ten.
You can then remove the greatest common divisor from the dividend and divisor and check if both of these numbers fit in the data type of your choice.
Python uses floating-point representation rather than rational numbers. Take a look at the standard library
fractions
module for some details about rational numbers.Observe, for example, this, to see why it goes wrong:
(Oh, you want to see a case where it works?)