Question

I have to write a program to find a rational number that has a property. I wrote the code to check the property, but now I don't know how to check all rational numbers. I tried with

float rat;
for (int i=1 ; i ; ++i) {
  for (int j=1 ; j ; ++j) {
    rat = (float)i/(float)j;
    if goodRat(rat) then return rat;
  }
}

but it never ends! And it misses too many. So then I tried this

float rat;
while {
  int i = random(1000) + 1;
  int j = random(1000) + 1;
  rat = (float)i/(float)j;
  if goodRat(rat) 
      return rat;
}

but this works only sometimes. How can I solve this?

Was it helpful?

Solution

The rational numbers are countable, which means that they can be put in one-to-one correspondence with the integers. If you do that, then you'll have your solution.

Instead of giving a one-to-one correspondence, an easier way to walk through the rationals is the following.

Construct an (countably) infinite by (countably) infinite matrix Q so that Q_(i,j) = i/j where i and j range from 1 to infinity. The matrix looks like this:

 1  1/2 1/3 1/4 1/5 . . .
2/1 2/2 2/3 2/4 2/5 . . .
3/1 3/2 3/3 3/4 3/5 . . . 
4/1 4/2 4/3 4/4 4/5 . . .
5/1 5/2 5/3 5/4 5/5 . . .
 .   .   .   .   .
 .   .   .   .   .
 .   .   .   .   .

Of course, there are many repeats (the entire diagonal is 1!), but I'm going for simplicity over speed.

What you're trying to do is walk down the columns, which are infinite, so you'll miss lots of numbers. Instead, you should walk along the anti-diagonals, which are finite. That is, take the elements in the following order

 1  3  6 10 15  . 
 2  5  9 14  .  .
 4  8 13  .  .  .
 7 12  .  .  .
11  .  .  .
 .  .  .
 .  .
 .

So you'll get 1, 2/1, 1/2, 3/1, 2/2, 1/3, 4/1, 3/2, 2/3, 1/4, .... Moreover, you know that you will encounter r/s at step (r+s)(r+s-1)/2 + s, so any given rational number will be encountered in finite time.

One way to code this is to let i be the row index (outer for loop) and let j be the column index (inner for loop). Then i will range from 1 to infinity, but j will only range from 1 to i.

If your goodRat function takes a fair amount of time, then you can speed this up by first testing that i and j are coprime, and if not skip them.

OTHER TIPS

The Stern–Brocot tree is one way to generate all rationals systematically without repetition. See others at https://math.stackexchange.com/questions/7643/produce-an-explicit-bijection-between-rationals-and-naturals.

First, about your first attempt:

float rat;
for (int i=1 ; i ; ++i) {
    // the loop for the first won't be reached
  for (int j=1 ; j ; ++j) {
  // this loop will never end, it will either loop for ever or return something like (floag)1/(float)j
    rat = (float)i/(float)j;
    if goodRat(rat) then return rat;
  }
}

My advice is , make your purpose clear, and maybe you can refer to http://en.wikipedia.org/wiki/Stern-Brocot_tree

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top