Finding factors of a given integer

Wilson picture Wilson · Dec 27, 2011 · Viewed 73k times · Source

I have something like this down:

int f = 120;
for(int ff = 1; ff <= f; ff++){
    while (f % ff != 0){            
}

Is there anything wrong with my loop to find factors? I'm really confused as to the workings of for and while statements, so chances are they are completely wrong.

After this, how would I go about assigning variables to said factors?

Answer

Tot Zam picture Tot Zam · Aug 21, 2017

The following code will return a list of all factors of a given number:

public ArrayList<Integer> findFactors(int num) {        
    ArrayList<Integer> factors = new ArrayList<Integer>();

    // Skip two if the number is odd
    int incrementer = num % 2 == 0 ? 1 : 2;

    for (int i = 1; i <= Math.sqrt(num); i += incrementer) {

        // If there is no remainder, then the number is a factor.
        if (num % i == 0) {
            factors.add(i);

            // Skip duplicates
            if (i != num / i) {
                factors.add(num / i);
            }

        }
    }

    // Sort the list of factors
    Collections.sort(factors);

    return factors;
}

This answer improves Sharad Dargan's answer in two ways:

  1. Based on an idea used in this answer, you can speed up the solution by determining the value to increment by, based on whether the number is even or odd.

    Add the following line of code before the for loop:

    int incrementer = num % 2 == 0 ? 1 : 2;
    

    Then change the last part of the loop to:

     i += incrementer
    

    If the number is odd, it then will skip all even numbers, rather than always incrementing by one no matter what.

  2. Sharad stores the upper limit value in a variable and then uses that variable in the for loop:

    int upperlimit = (int)(Math.sqrt(a));
    ...
    for(int i = 1; i <= upperlimit; i+= 1)
    

    Instead, place Math.sqrt(num) directly in the for loop and skip the upper limit variable:

    for (int i = 1; i <= Math.sqrt(num); i += incrementer) {
    

    This will allow you to skip the casting part of the code, creating cleaner code.


Some JUnit test cases you can then use:

@Test
public void test12() {
    FindFactors find = new FindFactors();

    int num = 12;
    List<Integer> factors = Arrays.asList(1, 2, 3, 4, 6, 12);

    assertEquals(factors, find.findFactors(num));
}

@Test
public void test1000000() {
    FindFactors find = new FindFactors();

    int num = 1000000;
    List<Integer> factors = Arrays.asList(1, 2, 4, 5, 8, 10, 16, 20, 25, 32, 40, 50, 64, 80, 100, 125, 160, 200,
            250, 320, 400, 500, 625, 800, 1000, 1250, 1600, 2000, 2500, 3125, 4000, 5000, 6250, 8000, 10000, 12500,
            15625, 20000, 25000, 31250, 40000, 50000, 62500, 100000, 125000, 200000, 250000, 500000, 1000000);

    assertEquals(factors, find.findFactors(num));
}

@Test
public void test1() {
    FindFactors find = new FindFactors();

    int num = 1;
    List<Integer> factors = Arrays.asList(1);

    assertEquals(factors, find.findFactors(num));
}

@Test
public void test0() {
    FindFactors find = new FindFactors();

    int num = 0;
    List<Integer> factors = new ArrayList<Integer>();

    assertEquals(factors, find.findFactors(num));
}