简体   繁体   中英

Find the largest prime factor of a given number

I am writing this method which should return the largest prime factor of a given number. It was working fine till 45 was entered and the output was 15, even though the output should be 5. I am struggling to find the bug. Please help.

public static int getLargestPrime(int number) {

        if (number < 0) {
            return -1;
        }

        for (int i = number-1; i > 1; i--) {
            if (number % i == 0) {
                for (int j = 2; j < i; j++) {
                    if (i % j == 0) {
                        continue;
                    }
                    return i;
                }
            }
        }
        return -1;

    }

You need to add a flag to check the divisibility of the value i . It will remain true only if i is a prime number. Later if the flag remains true, you can return i else you need to continue iterating

What's happening in your code is that when i=15, and the inner loop starts iterating starting from 2, 15%2!=0 so it skips the if condition and returns 15

for (int i = number-1; i > 1; i--) {
        if (number % i == 0) {
            bool flag = true;
            for (int j = 2; j < i; j++) {
                if (i % j == 0) {
                    flag = false;
                    break;
                }
            }
            if(flag)
                return i;
        }
    }

In short: The "prime" validation is wrong.

In your code, in the inner loop, you expect all numbers will be factors of "i", which is of course wrong.

Your code will retrieve the largest factor of your input, which there is a number which is not a factor of it (i % j,= 0). therefore the largest factor of it (regardless of primality).

  1. Find the prime numbers before the input number
  2. Sort the prime numbers in reverse order
  3. Iterate over the prime numbers and check whether its an exact multiple
  4. If its an exact multiple return the prime number
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

class PrimeFactorTest {

    public static void main(String[] args) throws Exception {
        int[] inputs = new int[]{-100, -25, -2, -1, 0, 1, 2, 3, 4, 5, 100, 1223, 2000, 874032849,
            Integer.MAX_VALUE, Integer.MAX_VALUE};

        for (final int input : inputs) {
            Optional primeFactor = largestPrimeFactor(input);
            if (primeFactor.isPresent()) {
                System.out.println("Largest Prime Factor of " + input + " is " + primeFactor.get());
            } else {
                System.out.println("No Prime Factor for " + input);
            }
        }
    }

    public static Optional<Integer> largestPrimeFactor(final int input) {
        if (input < 0) {
            return largestPrimeFactor(Math.abs(input));
        }
        final int sqrt = (int) Math.sqrt(input);
        List<Integer> primes = getPrimesInDescendingOrder(sqrt);
        if (primes.size() == 0) {
            return Optional.empty();
        }
        for (final int prime : primes) {
            if (input % prime == 0) {
                return Optional.of(prime);
            }
        }
        return Optional.of(input);
    }

    private static List<Integer> getPrimesInDescendingOrder(final int input) {
        if (input < 2) {
            return new ArrayList<>();
        }
        List<Integer> primes = new ArrayList<>();
        primes.add(2);
        for (int current = 3; current <= input; current++) {
            boolean isPrime = true;
            for (int prime : primes) {
                if (current % prime == 0) {
                    isPrime = false;
                }
            }
            if (isPrime) {
                primes.add(current);
            }
        }
        primes.sort(Collections.reverseOrder());
        return Collections.unmodifiableList(primes);
    }
}

I came up with this. If you start at 2 and work up the way, you are eliminating all the non-primes before you hit them, as they will no-longer be factors of the remainder.

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class LargestPrimeFactor {
    @Test
    public void testGetLargestPrime() {
        assertEquals(2, getLargestPrime(2));
        assertEquals(3, getLargestPrime(3));
        assertEquals(2, getLargestPrime(4));
        assertEquals(5, getLargestPrime(5));
        assertEquals(3, getLargestPrime(6));
        assertEquals(7, getLargestPrime(7));
        assertEquals(2, getLargestPrime(8));
        assertEquals(3, getLargestPrime(9));
        
        assertEquals(23, getLargestPrime(23*23*7*2*5*11*11));
    }

    int getLargestPrime(int number) {
        for (int i = 2; number > i; i++) {
            while (number > i && number % i == 0) {
                number = number / i;
            }
        }
        return number;
    }
}

It wasn't working fine until it reached 45. It failed for 4, 8, 12, 16, 18, 20, 24, 27, 28, 30, 32, 36, 40, 42, and 44. It returned -1 for every prime number, which is correct, but it also returned -1 for 4. It usually finds the largest factor, regardless of whether it's prime.

Your outer loop finds factors, starting with the largest. Your inner loop doesn't make sense. It needs to have a test for primality. It looks like you meant it to quit when it finds a factor of i, but it doesn't do that. Instead, it quits when it finds a number that isn't a factor. The continue statement tells it to go to the next value of j. You probably meant for it to go on to the next value of i. To do that, you could use break. That would bail out of the inner loop. Or you could label the outer loop and use the label in the continue statement, which is probably what you had in mind:

candidates:
for (int i = number - 1; i > 1; i--) {
  if (number % i == 0) {
    for (int j = 2; j < i; j++) {
      if (i % j == 0) {
        continue candidates; // This continues the outer loop
      }
      return i;
    }
  }
}
return -1;

That gets you closer, but it still fails for powers of two, and for cases where it finds p^n where p is a prime number.

Also, there's no point in starting the outer loop with number-1. You can skip all the numbers higher than number/2. None of them will produce a modulo of zero.

I would recommend doing something like this. First, consider 2*2*3*47 = 564 . The square root of 564 is <= 24 . So all you need to do is divide by numbers up to 24 . First, eliminate 2 . That leaves 3*47 . Next is 3 which leaves 47 . Since no other number from 4 thru 24 divides 47 , 47 must be a prime. If it were composite, it's prime factors would have been factored out by one of the earlier divisors.

This can be further optimized by factoring out 2 in a separate loop. Then starting with 3 , start dividing by only the odd numbers ( 2 already eliminated the even factors if there were any).

If the situation arises when the number is reduced to 1, then the last divisor that did the reduction must be the largest prime.

int[] testData = { 2, 10, 2 * 2 * 5, 2 * 3 * 47 * 5,
        2 * 2 * 2 * 3 * 3 * 3 * 17 * 17 * 17 };
for (int v : testData) {
    System.out.printf("%8s - largest prime factor = %s%n", v,
            getLargestPrime(v));
}

Prints

       2 - largest prime factor = 2
      10 - largest prime factor = 5
      20 - largest prime factor = 5
    1410 - largest prime factor = 47
 1061208 - largest prime factor = 17

The method

public static int getLargestPrime(int number) {
    // no primes less than 2 exist.
    if (number < 2) {
        return -1;
    }
    while (number % 2 == 0) {
        number /= 2;
    }
    
    int lastDivisor = 2;
    for (int d = 3; d <= Math.sqrt(number); d += 2) {
        lastDivisor = d;
        while (number % d == 0) {
            number /= d;
        }
    }
    
    return number == 1 ? lastDivisor : number;
}

This code will help you find the largest prime number. Most online servers won't allow it to run. Just change the value of n.

public class PrimeExample{    
         public static void main(String args[]){          
          for(int n = 100;n<=1000;n++){
           int i,m=0,flag=0; 
              m=n/2;      
              if(n==0||n==1){  
               System.out.println(n+" is not prime number");      
              }else{  
               for(i=2;i<=m;i++){      
                if(n%i==0){      
                 System.out.println(n+" is not prime number");      
                 flag=1;      
                 break;      
                }      
               }      
               if(flag==0)  { System.out.println(n+" is prime number"); }  
            }//end of else  
          }
        }    
    }  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM