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?
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.
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
精彩评论