2016-10-19 12 views
-1

У меня есть простой метод Java, который, как предполагается, вычисляет список простых делителей определенного числа.Почему эта ошибка Java-функций?

public class Factors { 



public static List<Integer> fac(List<Integer> factors, int number) { 
    if(number < 2) { 
     throw new IllegalArgumentException("Number must be greater than one"); 
    } 


    for (int i = 2; i <= number; i++) { 
     while (number%i == 0) { 
      factors.add(i); 
      number /= i; 
     } 
    } 
    return factors; 
} 
public static void main(String [] args) 
{ 
final long startTime = System.currentTimeMillis(); 

    ArrayList<Integer> factors = new ArrayList<>(); 
    System.out.println(fac(factors, 2147483647)); 

final long endTime = System.currentTimeMillis(); 
System.out.println("Total execution time: " + (endTime - startTime)); 
} 
} 

Этот код отлично работает, за исключением того, что вы передаете Integer.MAX_VALUE; в этом случае, давая:
java.lang.OutOfMemoryError: Java heap space
Первоначально я думал, что это связано с тем, что инициализация ArrayList находилась внутри метода, но после удаления такая же ошибка сохраняется.
Кроме того, это:

public static List<Long> facrec2(List<Long> list, long number) { 
    if (number < 2) { 
     return list; 
    } 

    if (number == 2) { 
     list.add(2L); 
     return list; 
    } 

    for (long i = 2; i <= number; i++) { 
     while (number % i == 0) { 
      number /= i; 
      list.add(i); 
      return facrec2(list, number); 
     } 
    } 
    return null; 
} 

метод работает для макс значений (после изменения подписи к Integer, работает на целое значение макс тоже). Логика как предполагается, одна и та же, только рекурсивная реализация второй делает разницу ...

+0

+1. Я думаю, что вы могли бы лучше отлаживать работу (или, по крайней мере, демонстрировать вашу отладку), но удивительно тонко, как эта ошибка приводит к этому исключению. – ruakh

+0

Да, но я получил обе функции от кого-то еще, как пример, и с нетерпением отправил на stackoverflow, вместо того, чтобы заставить себя работать :) –

+0

'Логика [итеративная и рекурсивная обработка любого данного предполагаемого пробного делителя] должна быть то же самое - с рекурсией, вы _never_ получаете, чтобы увеличивать (и перечитывать) 'i' после обнаружения' i' делит то, что осталось от 'number'. – greybeard

ответ

1
for (int i = 2; i <= number; i++) { 

Проблема здесь. Если number == Integer.MAX_VALUE этот цикл никогда не завершится. Как только i получает до Integer.MAX_VALUE, следующий приращение устанавливает его на Integer.MIN_VALUE, что очень отрицательно, и цикл продолжает выполняться, поэтому вы будете постоянно добавлять в список навсегда и исчерпать память.

Самое простое решение заключается в изменении состояния цикла в < и обрабатывать случай, когда number все еще имеет свою первоначальную стоимость по отдельности (то есть случай, когда number является первичным). Вы также можете выйти из цикла number == 1.

+1

+1. Обратите внимание, что когда 'i' получает значение' Integer.MAX_VALUE', 'number' устанавливается в' 1'; но так как 'i' получает значение' Integer.MIN_VALUE' сразу же после этого, он по-прежнему остается меньше, чем 'number'. И тогда 'i' в конечном итоге достигает' 1', после чего 'number% i == 0' постоянно истинно, поэтому список заполняется произвольно большим количеством' 1', пока не закончится память. Просто невезение «Integer.MAX_VALUE» оказывается простым. :-) – ruakh

+0

Да, именно так. первая функция при изменении while, если дает [2147483647, -1], но дает неправильные ответы, для 120, например, возвращает 2, 3, 4, 5 (4 не является простым). Поэтому, хотя это важно, и функция нуждается в исправлении, которое вы предложили. Второй кажется, все в порядке. –

+0

Неверное изменение 'while/if', которое не было мной, теперь удалено. Вам нужно 'while', чтобы получить основные факторы. – EJP

0

Этот цикл никогда не заканчивается. Когда счетчик i достигнет Integer.MAX_VALUE, он перевернется. Вы не должны допускать равенства в условии цикла.