Algorithm to generate positive rational numbers in Java

Rational Numbers − A number that is expressed in the form of p/q. Given the condition that p and q both should be integers and q should not be equal to 0.
Positive rational numbers are those numbers whose final values are positive. For this, either p and q both should be positive or p and q both should be negative.
In this problem to generate positive random numbers up to a given number. We have to generate a finite number of positive rational numbers to n i.e. we will find rational numbers between 1 to n. For this algorithm, we will generate random numbers where 1 <= p <= n and 1 <= q <= n.
Let's take an example to elaborate on the concept better −
Input : 3
Output : 1, 1⁄2 , 1⁄3 , 2 , 2⁄3 , 3/2 , 3 .
Explanation − In this example, we will consider values between 1 to 3 for both p and q.
The algorithm designed for this will work using sets which are the best data structures for optimally generating the required combinations. As sets can be mapped and mapping can be of the order n to n i.e. each value in set1 can be mapped properly with values in set2 creating a mapping that can generate the required pairs. For generating the required pairs we will use to sets of positive values and map the values to get the solutions.
Let’s take an example,
(1,1) , (1,2) , (1,3)
(2,1) , (2,2) , (2,3)
(3,1) , (3,2) , (3,3)
Let's re-arrange these values in an inverted L shape traversal method −
(1,1)
(1,2) , (2,2) , (2,1)
(1,3) , (2,3) , (3,3) , (3,2) , (3,1)
These are the values that we have used in generating positive rational algorithm examples. For better understanding that we have yielded the exact same values just replace the, with ∕ to get these values −
1/1
1/2 , 2/2 , 2/1
1/3 , 2/3 , 3/3 , 3/2 , 3/1
Though there are values like 1∕1, 2∕2, 3∕3 that point to the same value. We will eliminate these values using the greatest common divisor.
import java.util.ArrayList;
import java.util.List;
class PositiveRational {
   private static class PositiveRationalNumber {
      private int numerator;
      private int denominator;
      public PositiveRationalNumber(int numerator, int denominator){
         this.numerator = numerator;
         this.denominator = denominator;
      }
      @Override
      public String toString(){
         if (denominator == 1) {
            return Integer.toString(numerator);
         } else {
            return Integer.toString(numerator) + '/' +
            Integer.toString(denominator);
         }
      }
   }
   private static int gcd(int num1, int num2){
      int n1 = num1;
      int n2 = num2;
      while (n1 != n2) {
         if (n1 > n2)
            n1 -= n2;
         else
            n2 -= n1;
      }
      return n1;
   }
   private static List<PositiveRationalNumber> generate(int n){
      List<PositiveRationalNumber> list = new ArrayList<>();
      if (n > 1) {
         PositiveRationalNumber rational = new PositiveRationalNumber(1, 1);
         list.add(rational);
      }
      for (int loop = 1; loop <= n; loop++) {
         int jump = 1;
         if (loop % 2 == 0)
            jump = 2;
         else
            jump = 1;
         for (int row = 1; row <= loop - 1; row += jump) {
            if (gcd(row, loop) == 1) {
               PositiveRationalNumber rational = new PositiveRationalNumber(row, loop);
               list.add(rational);
            }
         }
         for (int col = loop - 1; col >= 1; col -= jump) {
            if (gcd(col, loop) == 1) {
               PositiveRationalNumber rational = new PositiveRationalNumber(loop, col);
               list.add(rational);
            }
         }
      }
      return list;
   }
   public static void main(String[] args){
      List<PositiveRationalNumber>rationals = generate(5);
      System.out.println(rationals.stream().
      map(PositiveRationalNumber::toString).
      reduce((x, y) -> x + ", " + y).get());
   }
}
1, 1/2, 2, 1/3, 2/3, 3/2, 3, 1/4, 3/4, 4/3, 4, 1/5, 2/5, 3/5, 4/5, 5/4, 5/3, 5/2, 5