Java: получить наибольший общий делитель, какой метод лучше?

Из этого вопроса Java: получить наибольший общий делитель

При получении gcd любого типа данных, будь то int, long, Integer, Long, какой ответ лучше с точки зрения точности, скорости, использования процессора и т. д.?

A:

private static int gcdThing(int a, int b) {
    return BigInteger.valueOf(a).gcd(BigInteger.valueOf((b))).intValue();
}

B:

public int GCD(int a, int b) { return b==0 ? a : GCD(b, a%b); }

person Marl    schedule 05.02.2014    source источник
comment
Попробуй это. Создайте список или массив из множества чисел и проверьте время выполнения каждого из них. Изменить: вероятно, это не BigInteger, потому что он работает медленно даже с настройками.   -  person Xabster    schedule 05.02.2014
comment
Если вы измените второй метод с рекурсивного на итеративный, он, вероятно, даст наилучшие результаты.   -  person Nir Alfasi    schedule 05.02.2014
comment
О, хорошо, я еще не пробовал бенчмаркинговые коды. Думаю, я просто испытаю это на себе.   -  person Marl    schedule 05.02.2014
comment
Если последнее, что вы делаете перед возвратом, — это рекурсия, то это хвостовая рекурсия, и ее почти всегда лучше преобразовать в цикл. (Рекурсия, как правило, НЕ лучший ответ, если проблема может быть решена так же легко с помощью цикла, и часто не лучший ответ, даже если он не может.)   -  person keshlam    schedule 05.02.2014
comment
B - интересный алгоритм. Кажется, работает, но в этот поздний час у меня возникли проблемы с объяснением себе, почему это должно работать.   -  person keshlam    schedule 05.02.2014
comment
Почему не был рассмотрен stackoverflow.com/a/4009467/2161613... Я ожидаю, что вычитание будет намного быстрее, чем разделение.   -  person whossname    schedule 03.08.2015


Ответы (1)


    Random r = new Random();
    int[] ints = new int[500000];
    for (int i = 0 ; i < ints.length ; i++)
        ints[i] = r.nextInt();

    for (int i = 0 ; i < ints.length-1; i++)
        GCD(i,i+1);
    for (int i = 0 ; i < ints.length-1; i++)
        gcdThing(i, i + 1);

    long start = System.currentTimeMillis();
    for (int i = 0 ; i < ints.length-1; i++)
        GCD(i,i+1);
    System.out.println("GCD: " + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    for (int i = 0 ; i < ints.length-1; i++)
        gcdThing(i, i + 1);
    System.out.println("gcdThing: " + (System.currentTimeMillis() - start));

Отпечатки:

НОД: 13

gcdThing: 124

person Xabster    schedule 05.02.2014
comment
Ну, это отвечает на него. - person Marl; 05.02.2014
comment
На самом деле этого недостаточно, чтобы дать серьезный ответ о скорости после JIT... но это результат, которого я ожидал. С другой стороны, я готов поспорить, что итеративное решение будет еще быстрее, особенно после JITting. - person keshlam; 05.02.2014
comment
@keshlam Думаю, я тоже попробую итерацию, чтобы проверить лучшую производительность. - person Marl; 05.02.2014
comment
@keshlam 50 миллионов дает: GCD: 1246 gcdThing: 14114, и разминка немного длиннее, чем сумма этих чисел, но я не считаю время разминки. - person Xabster; 05.02.2014
comment
Кроме того, @keshlam, можете ли вы указать, что вам нужно вызывать метод более 50000 раз для прогрева? Потому что я не могу. - person Xabster; 05.02.2014
comment
Зависит от сложности кода и того, какую именно JVM вы используете (и какие критерии она использует для запуска каких этапов оптимизации). Эмпирическое правило, с которым я работал, это пять минут разминки, но я также работал с гораздо более сложными системами. К сожалению, лучшие ссылки, которые я могу придумать, не являются общедоступными. - person keshlam; 05.02.2014
comment
(А с более сложными системами вы также можете столкнуться с тем фактом, что поведение JIT может быть не полностью детерминированным. Серьезный бенчмаркинг Java может запутаться.) - person keshlam; 05.02.2014
comment
Конечно, измерение в секундах реального времени не является правильным способом сделать это. Это последняя сборка раннего доступа JRE 8, скомпилированная с помощью javac из того же. Я думаю, вы сильно усложняете эту вещь. Это не корпоративный сервер с 1000 тыс. LOC. - person Xabster; 05.02.2014