RationalQ – Testing for rationals in Mathematica
Mathematica has a large set of functions that you can use to test the properties of numbers. For example
IntegerQ[x]
returns True if x is an integer and False if it isn’t. Of course you are not just restricted to asking if x is an integer or not. For example, you can ask if it is an even number
EvenQ[x]
or an odd number
OddQ[x]
Perhaps you are wondering if x is prime
PrimeQ[x]
or even if it is an algebraic integer
AlgebraicIntegerQ[x]
The observant reader will notice that all of these functions end with a capital Q and a way of remembering this is to think that you are asking a question of the variable x. So the question ‘Is x an integer‘ becomes, in Mathematica notation, IntegerQ[x].
I am currently working on a piece of code where I need to determine whether or not a particular number belongs to the set of rationals and I assumed that a suitable function would exist in Mathematica and that it would be called RationalQ[] so I was rather surprised to see that there is no such function in Mathematica 7.
So, I’ll just have to come up with my own. A quick search resulted in the following function definition from Bob Hanlon
RationalQ[x_] := (Head[x] === Rational)
Which almost does what I need. It handles the following correctly
RationalQ[1/2] (gives True)
RationalQ[Sqrt[2]] (Gives False)
but I needed a version of RationalQ that also returned True when passed an integer. After all, the integers are just a subset of the rationals. A moments thought resulted in
RationalQ[x_] := (Head[x] === Rational || IntegerQ[x]);
Which seems to work perfectly. So, I offer the above function for anyone who is googling for a RationalQ function and I also ask the following questions to any Mathematica gurus who might be reading this
- Is there anything wrong with the above definition?
- Why isn’t such an obvious function not included in Mathematica as standard?
IntegerQ is a function that tests whether the /data type/ of an expression is Integer, but not whether something is mathematically an integer. Therefore it is really redundant, Head[something] === Integer works the same. Use Simplify[something \[Element] Integers] to test if something is an integer mathematically (as the documentation suggests). Or, alternatively, FullSimplify.
You did not tell us what you wanted to use this RationalQ function for, so I can’t really tell you if there is anything wrong with it. Here are a few examples where it might go wrong:
For your particular application, do you consider the Mathematica expression 1.2 a rational number? Do you consider the expression Cos[\[Pi]/8]^2 – 1/(2 Sqrt[2]) a rational number? (Its value is 1/2, but it is not automatically simplified by Mathematica.)
I hope this helps,
Szabolcs
Or you could use Element[x,Rationals]
Hi Mike,
There is also no object like RealQ or ComplexQ, this is because Mma has a set of predefined domains,
Reals, Integers, Complexes, Algebraics, Primes, Rationals and Booleans
You can ask if something (x) is in a domain using
Element[x, domain]
It works this way since these are the domains that you can tell Reduce (and other functions) to work in — also they can be passed to Assumptions – ie they work for variables as well as numbers.
As for your code, it should work for any numerical object you want to test…
but if you’ve your using the assumptions (say, set globally)
$Assumptions = {Element[n,Integers]}
then
(n/2) \[Element] Rationals // Simplify
returns
True
but would return False with your code.
In fact that reminds me of a place where your code might troublesome:
If[RationalQ[x/2], Print[“ok”], Print[“not ok”]] /. x -> 2
would return
“not ok”
with your definition – since if RationalQ will always return False if it’s not an integer or rational.
It is better to leave the undecided case unevaluated, so the following code would be more robust:
RationalQ[x_Integer] := True
RationalQ[x_Rational] := True
and (remembering to Clear the previous definition of RationalQ)
If[RationalQ[x/2], Print[“ok”], Print[“not ok”]] /. x -> 2
returns
“ok”
If you want to force an answer you can always use
RationalQ[x/2]===True
in a conditional.
sorry for the essay!
Simon
PS
my indenting was removed by your blogging software — I probably should have used html tags…
Beware of this oddity:
It’s possible to use the Rational constructor to form perverse rationals such as
p = Rational[π,3]
(That’s pi over 3).
What exactly is that thing? Let’s take a look numerically:
In[2]= N[p]
Out[2]= 3.14159 /3
That’s sort of numerical, put not quite all the way flattened for some reason.
Applying the N hammer once more
In[3]= N[%]
Out[3]= 1.0472
So this creature does have a normal numeric value, but yet p would be considered
Rational, since its head is Rational.
Mike,
I’m using almost the same thing, although mine is 3 definitions:
RationalQ[x_Rational] := True
RationalQ[x_Integer] := True
RationalQ[x_] := False
I’m using the pattern matching directly, which is probably faster (not tested).
Cheers,
Sander
Thanks for all of the comments people. My function works just fine for my particular application but it obviously has issues that are addressed by your solutions.
I was thinking…from a certain point of view, ALL floating point numbers belong to the rationals since they all have a finite number of decimal places. This is almost certainly not what people expect though.
Thanks again for the discussion,
Mike
A comment on a previous comment:
While it is possible to write things like Rational[Pi,3] or Complex[a,b], these symbols (Rational and Complex) were not intended to be used this way (i.e. for building expressions). Doing it anyway just invites trouble.
The properly written expression Pi/3 or Divide[Pi,3] does not have head Rational (its FullForm is Times[Rational[1,3], Pi]).
Another comment on the same previous comment:
Hi I. J. Kennedy, I tried to reproduce your results using Mathematica 7.0 for Linux x86 (64-bit), but got something different,
In[1]:= p=Rational[\[Pi],3]
Out[1]= Rational[\[Pi],3]
In[2]:= N[p]
Out[2]= 3.14159/3.
In[3]:= N[%]
Out[3]= 3.14159/3.
In[4]:= FixedPoint[N,p]
Out[4]= 3.14159/3.
obviously if you cut and paste the output, you get
In[5]:= N[3.141592653589793`/3.`]
Out[5]= 1.0472
Also, here’s a quick and dirty timing test:
In[1]:= {r,f}={1/3,.3};
reps=10^6;
In[3]:= $TimeUnit
Out[3]= 1/100
In[4]:= ClearAll[RationalQ];ClearSystemCache[]
RationalQ[x_]:=(Head[x]===Rational||IntegerQ[x]);
Timing[Do[RationalQ/@{r,f},{reps}]]
Out[6]= {11.1807,Null}
In[7]:= ClearAll[RationalQ];ClearSystemCache[]
RationalQ[x_Integer]:=True
RationalQ[x_Rational]:=True
Timing[Do[RationalQ/@{r,f},{reps}]]
Out[10]= {5.20433,Null}
In[11]:= ClearAll[RationalQ];ClearSystemCache[]
RationalQ[x_]:=Element[x,Rationals]
Timing[Do[RationalQ/@{r,f},{reps}]]
Out[13]= {6.02838,Null}
As others have noted, your function will test whether a number is in the DOMAIN of RATIONALs, but will not accurately test if a number is mathematically in the field of rationals. For example, apply your function to the number 2.54678. It will return FALSE.
There is not a simple test, to the best of my knowledge, for determining whether a given real number is rational or not, if you do not already know its numeric representation. For example, it is still not known whether e+pi is rational or irrational (although it is known that e+pi and e*pi cannot both be rational – see this Math Overflow post: https://mathoverflow.net/questions/40145/irrationality-of-pi-e-pi-pi-and-e-pi2). If there were a simple algorithm to test the rationality of a number, then this would surely be known by now. To determine whether a given real is mathematically rational, the brute force test would be to multiply it by successive integers and stop when the result is an integer. That would prove that it is rational. Unfortunately, if you never get an integer result, you still can’t be sure that it is not rational. The number might be a string of trillions or random digits that ends at some point, but is so long that even the fastest computer today could never complete the brute force test. The method of continued factions (which Mathematica handles quite efficiently) would be a faster test, but alas, even that would never end for an irrational number.