Няшная / Говнокод #3695 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
#include <stdio.h>

void factorization(int num, int show) {
    int num1 = num;
    int n = 2;
    while ( n*n <= num1 ) {
        if ( num%n == 0 ) {
            num = num / n;
            if ( show )
                printf( "%d\n", n );
        } else {
            n ++;
        }
    }
}

int main() {
    int i = 0;
    while ( i < 1000 ) {
        factorization(999999, 0);
        i ++;
    }
    return 0;
}

Опубликовано в одной из ссылок с http://habrahabr.ru/blogs/ruby/48952/ (если надо, точную ссылку найду позже).
Код раскладывает число на простые множители тупым перебором делителей. Мало того, что этот код медленный, так он иногда последний множитель пропускает. Одновременно и ошибка, и скорость исправляются так:
- while ( n*n <= num1 ) {
+ while ( n <= num ) {
Неожиданно, правда?

Запостил: inkanus-gray inkanus-gray, (Updated )

Комментарии (18) RSS

  • Это же тест на скорость. Нашёл к чему придираться, пипец.
    Ответить
    • Соглашусь. Поскольку это тест на скорость, код не обязан быть оптимальным.
      Ответить
  • У него руби победил с 287 мс, а у меня .NET выполнил тот же тест за 7 мс хыхы (что моно, что MS NET)

    Ну ладно, пусть детишки дальше в игрушки играются
    Ответить
    • Отсюда мораль: не верить ничему, что пишут на околокомпьютерных ресурсах.
      Ответить
        • я там ржал, когда увидел статейку "Программирование микроконтроллеров для начинающих"
          Ответить
          • Всё когда-то начинается. Для начинающих в программировании контроллеров.
            К тому же микроконтроллер это всё таки не большой адронный коллайдер.
            Так что имеет место быть.
            Ответить
  • >>>>Одновременно и ошибка, и скорость исправляются так:
    >>>>while ( n*n <= num1 ) {
    >>>>+ while ( n <= num ) {
    Ыыы)))
    да что вы тут такое пишете - вы походу вообще не в теме

    1. перебирать надо до (корня от n)+1 - вычисленного 1 раз (квадратичный спид-ап) именно для этого там n*n, но зачем каждый раз умножать если можно взять корень от num1
    2. перебирать надо нечетные со степом 2 - спид-ап в два раза от пункта 1,
    проверив предварительно двойку
    3. если хотим большего надо пользовать формулу 6k+1, 6*k-1 - спидап в полтора раза от пункта 2.

    это самое примитивное, если найду запостю труЪ алгоритм, короче самое быстрое что мне удавалось писать раскладывало числа до 2^64 менее чем за секунду кажись.
    правда это был асм, FPU, SSE и еще пару хитрых оптимизаций
    Ответить
    • код - безусловное с точки зрения скорости говно, инканус - ты не обижайся твоя оптимизация тоже Г

      вообще если кому надо математическое обоснование - пишите.
      ЗЫ в пункте 3 надо сначало проверить 2 и 3 а потом юзать формулу 6k+1, 6*k-1
      Ответить
      • вот примерно таким образом ищется первый делитель.
        несложно сделать из этого факторизацию, даже рекурсивный способ должен работать быстрее вышеприведенных

        if ( num%2 == 0 ) return 2;
        if ( num%3 == 0 ) return 3;
        int root=((int) sqrt(num))+1;
        int k=(root/6)+1;

        for (int i=1,div=0;i<k;i++){
        div+=6;
        if ( num%(div-1) == 0 ) return (div-1);
        if ( num%(div+1) == 0 ) return (div+1);
        }
        //число простое
        return -1;
        Ответить
    • Никаких обид. Про необходимость пропускать чётные я хотел написать, но не стал писать умышленно, потому что мне было интересно, заметит ли кто-нибудь. Пропускать тройки тоже неплохо. А вот дальше, боюсь, оптимизация будет сомнительной.
      Про корень от num1 я тоже думал, но с ним получается медленнее. Надо будет выяснить, почему.

      Кто-нибудь заметил, что в предложенном патче num вместо num1? Цикл автоматически остановится на последнем множителе.
      Pro et contra
      Pro: в данном примере последняя итерация будет, когда n == num == 37 вместо n == sqrt(num1) == 999.
      Contra: для чисел вида 2*x, 3*x, 5*x, где x — простой множитель, намного больший, чем sqrt(num1), будет медленно.
      Резюме: использовать комбинированное условие для завершения.
      Ответить
      • Про корень вру. С корнем всего на 5% быстрее, а хотелось бы больше.
        Ответить
        • попробуй числа побольше, начиная с 2^24 ))
          ибо корень первая и наиглавнейшая оптимизация
          Ответить
      • >>>>А вот дальше, боюсь, оптимизация будет сомнительной.
        нет, 30*n и исключение 5 - точно быстрее, дальше - зависит от того какие простые числа,
        если маленькие - увеличивается размер кода, и он не влазит в L1 - что снижает скорость
        если большие - там можно цикл намутить и бренчинг кроется выигрышем в пропусках чисел кратных 7 и 11
        но тут надо генить таблицу.
        30*n - весьма оптимальное и простое сочетание

        >>>>Про корень от num1 я тоже думал, но с ним получается медленнее.
        никак нет, выигрыш в скорости - просто нереальный (квадратичный), попробуй то что я набросал на числах около 100 миллионов.
        пример так надо перебирать до миллиона - n
        а так до тысячи - корень из n
        но ВАЖНО корень он не для факторизации - он для проверки на простоту (или поиска первого делителя)
        Ответить
        • вообще по этой теме можно диссертации писать.
          тут для разных диапазонов чисел разные оптимальные алгоритмы ))))
          Ответить
        • вообще самая быстрая проверка - это сгенить таблицу простых чисел,
          но т.к. в те времена когда я этим занимался она не влазила в мои 512Мб, пришлось делать хитрые вещи - типа этих 6*n и 30*n, а хранить числа либо как массив битов простое - не простое (причем хранились только значения для n) (и массив битов - на самом деле был байтовым)

          либо как разницу между простыми числами, деленную пополам т.к. она почти всегда была меньше байта, то одно простое число занимало байт.
          + у меня был массив исключений для разниц, которые были больше 512 (напоминаю я делю разницу пополам, поскольку она всегда четная)
          Ответить
          • >>>(и массив битов - на самом деле был байтовым)
            то есть я получал биты через инлайн-спец-функцию меняющую бит адресацию на байт и извлекающую их из байтового массива
            Ответить
      • >>>>Contra: для чисел вида 2*x, 3*x, 5*x, где x — простой множитель, намного больший, чем sqrt(num1), будет медленно.

        а мы х - будем проверять на простоту тоже по корню )))) если простое - напечатали и вышли, нет - нашли множитель итд..
        я же сказал рекурсивно, но я делал и без рекурсии
        Ответить

Добавить комментарий

Семь раз отмерь — один отрежь, guest!

    А не использовать ли нам bbcode?


    8