1. C++ / Говнокод #2243

    +54.7

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    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
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    int NOD(int a,int b)
    		{
    			if(a==0)
    			{
    				return b;
    			}
    			if(b==0)
    			{
    				return a;
    			}
    			if(a==b)
    			{
    				return a;
    			}
    			if((a%2==0)&&(b%2==0))
    			{
    				return 2*NOD(a/2,b/2);
    			}
    			else if((a%2==0)&&(b%2!=0))
    			{
    				return NOD(a/2,b);
    			}
    			else if((a%2!=0)&&(b%2==0))
    			{
    				return NOD(a,b/2);
    			}
    			else if((a%2!=0)&&(b%2!=0))
    			{
    				return NOD(b,abs(a-b));
    			}
    			else return 1;
    
    			/*
    			   1. НОД(0, n) = n; НОД(m, 0) = m; НОД(m, m) = m;
    			   2. НОД(1, n) = 1; НОД(m, 1) = 1;
    			   3. Если m, n чётные, то НОД(m, n) = 2*НОД(m/2, n/2);
    			   4. Если m чётное, n нечётное, то НОД(m, n) = НОД(m/2, n);
    			   5. Если n чётное, m нечётное, то НОД(m, n) = НОД(m, n/2);
    			   6. Если m, n нечётные, то НОД(m, n) = НОД(n, |m - n|).
    
    			*/
    		}

    Алгоритм Евклида - прошлый век!
    Нарыл в Wiki некий алгоритм)

    Запостил: zelenov.pavel, 07 Декабря 2009

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

    • Покажи современный способ.
      Ответить
    • А что Вас, собственно говоря, не устраивает? Реализация алгоритма, прямо скажем, удручающе прямолинейна (рекурсия и т.д.), но сам алгоритм-то имеет право на существование. Всегда хорошо иметь несколько вариантов решения одной задачи.
      Ответить
      • Симпатична 31 строчка. За одну ее плюсую!

        И да, давайте не будем показывать автору решето Эратосфена!
        Ответить
        • Чем она симпатична? Обычный выход из рекурсии. Может она в рекурсивной функции вычисления факториала, она тоже будет симпатична?
          Ответить
          • Факториал нужно не через рекурсию считать, ибо медленно и черевато переполнениями стека.
            Ответить
            • И да, рекурсию тяжело отлаживать. Факториал через for - самое то.
              Ответить
            • Я не говорю, что факториал надо рекурсией высчитывать, просто как пример привёл.
              Ответить
            • Стеком не чревато. Раньше переполнится арифметика. 74! перекрывает 1.0+E308.
              Ответить
          • Нет, в данном месте. Поскольку лишняя.
            Ответить
        • Классический алгоритм Евклида не содержит ни умножений, ни делений, ни контролей четности претендентов. Только вычитание - и в этом фишка. Выглядит примерно так.

          unsigned int NOD(unsigned int a, b) {
            if (a==b) return a;
            return (a>b)?NOD(a-b,b):NOD(a,b-a);
          }


          Все эти подпрыгивания с четностью и деленьями на 2 - попытки "т.н.оптимизации" решетом, из которого взята только двойка. Почему остатки от деления на 3 не проверяются?

          Хотя никакого решета не нужно. Если уж работать с делением, то можно сделать так.
          unsigned int NOD(unsigned int a, b) {
            if (a==b) return a;
            return (a>b)?NOD(a%b,b):NOD(a,b%a);
          }


          Так что в топку решето. Последний пример заруливает решето в минуса между вторым и третьим раундами.
          Ответить
    • Не говнокод и не говноалгоритм.
      >Алгоритм Евклида - прошлый век!
      У вас есть алгоритм нашего века?
      Ответить
      • Ну, то, как написано, не соответствует комментарию... Так что говнореализация уж как минимум.
        Ответить
      • >Не говнокод и не говноалгоритм.
        Как раз таки эта 30-строчная конструкция, имхо, отличный пример говнокода, в то время как алгоритм Евклида пишется в 5-6 строк))
        ">Алгоритм Евклида - прошлый век!" - сарказм, если что
        Ответить
        • "Я не доверяю алгоритмам, придуманным людьми, которые и слова-то такого не знали!"
          Ответить
        • Вообще, есть серьёзные подозрения, что данный алгоритм придуман именно для сдвига чётных чисел, так как после вычитания одно нечётного числа из другого снова будет чётное, которое можно сдвинуть. Таким образом за один шаг число всегда сдвигается на один разряд. Это может быть, скорее всего будет, более эффективное решение в двоичной арифметике, чем алгоритм Евклида.

          Естественно, что приведённая как "говнокод" версия плоха, она использует рекурсию и не сдвигает чётную разность перед следующим вызовом.
          Ответить
        • Там в педивикии написано, что это самая эффективная реализация Евклида? Нет. А для понимания, пмсм, как раз такая реализация подходящее. С делениями на 2, с else (потомушта на Pascal присваивание результата функции не прерывает выполнение).
          Ответить
          • На какая твоя говорить языка?
            (j/k)
            Ответить
            • Какое слово тебе не понятно? Есть академические реализации алгоритмов. В Энциклопедии вряд ли можно встретить другую реализацию, потому что она должна быть понятна всем и пояснять суть алгоритма. Приведенный автором поста пример - как раз такой. Например, проверка четности контролем остатка от деления на два, а не младшего бита - потому что все нормальные люди четность определяют ровно так (Евклид из них). В некоторых языках программирования (особенно академических) присваивание результата возврата функции не прерывает ее выполнение - отсюда многочисленные "else". В некоторых языках программирования (особенно академических) отсутствуют циклы - отсюда рекурсия. И само формальное описание алгоритма Эвклида - рекурсивное.

              Вы еще скажите, что считать числа Фибоначчи рекурсией неэффективно. Но описаны они именно реккурентным соотношением.

              Поэтому в посте не говнокод - а отличный школьный пример реализации алгоритма Евклида.

              fil teh pawer.
              Ответить
              • Я про язык написал к тому, что: "педивикии", "пмсм", "реализация подходящее", "потомушта".

                >считать числа Фибоначчи рекурсией неэффективно
                Да. Вообще считать рекурсией не эффективно, потому что каждый раз память забивается ненужной числовой информацией, а иногда очень большими числами, хотя хранить их в памяти не нужно.
                Ответить
                • Нельзя, камрад, так однозначно утверждать - "считать рекурсией неэффективно" - особенно упоминая "забившуюся память".

                  Например, в общем случае: вычисление длины кратчайшего пути выхода из лабиринта. Рекурсией неэффективно по времени, но требует гораздо меньше ресурсов по памяти. Нерекурсивным волновым методом получится быстрее, но памяти потребует - не горюй. Потому что рекурсия одновременно "помнит" один путь, а волновой метод - одновременно все возможные.

                  Такшта, каждому овощу - свой шесток. ;) А язык - дело наживное.
                  Ответить
                  • Считать рекурсией всегда неэффективно. Это всем известно и никому не интересно.
                    Другое дело, когда действительно нужно запомнить.
                    А в рядах, обычно, ничего запоминать не нужно, потому это и есть банальное забивание памяти.

                    А алгоритм Евклида, между прочим, ищет НОД последовательным делением с остатком, а не вычитанием.
                    Ответить
    • Вообще-то "nod" означает "кивок".
      Ответить
      • Но тут большими буквами, поэтому это, скажем, Night Observation Device.
        Ответить
    • А ещё бесит такая проверка на чётность. С настоящим делением на два.
      Ответить
      • Неужели такуж бесит? Не смотрите. И боже вас упаси, читать перед обедом отечественный говнокод....
        Ответить
      • А как вы предлагаете?
        Ответить
        • intNum & 0x01
          Ответить
          • тогда и деление/умножение на 2 сдвигами надо.
            Ответить
            • Конечно.

              Правда, существуют два поверья:
              1. компиляторы сами оптимизируют деление в сдвиг.
              2. компиляторы сами оптимизируют остаток от деления в конъюнкцию

              Лично я до сих пор пользуюсь двоичными операторами по привычке.
              Ответить
              • нормальные компиляторы действительно оптимизируют
                Ответить
                • Вообще, это такой вопрос из разряда "программных верований".
                  Нужно к каждому отдельному компилятору читать документацию, а ещё лучше разбираться в сгенерированном машинном коде. Ещё лучше именно для того приложения, которое должно работать, а не приём отдельно.

                  Вообще, я только за ту оптимизацию, которую глазом вижу, а не миллисекундами. Доли секунд вообще могут сожраться системой. (кстати тоже весело: Макконелл писал, что можно получать существенную оптимизацию, если писать код выровненными кусками; я ничего не понял, но впечатляет заморочка; связано с загрузкой кода в рабочую память процессора)

                  Вот если я сдвиг написал и у меня программа работает стабильно сорок минут вместо часа -- значит верно воткнуто =]
                  Ответить
    • евклид это далеко не прошлый век и даже не позапрошлый, марш бегом в школу!
      Ответить

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