1. Си / Говнокод #11847

    +141

    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
    #include <stdio.h>
    
    void swap(long *a,long *b){
      *a=(*a<<sizeof(*a)*4);
      *a+=*b;
      *b=*a ^ *b;
      *b=(*b>>sizeof(*a)*4);
      *a=(*a<<sizeof(*a)*4);
      *a=(*a>>sizeof(*a)*4);
    }
    
    int main(){
     long a=22807;
     long b=1012;
       printf("a=%ld b=%ld\n",a,b);
     swap(&a,&b);
      printf("a=%ld b=%ld\n",a,b);
    }

    Swap variables without third variable

    Запостил: AliceGoth, 29 Сентября 2012

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

    • http://ideone.com/eCVss
      FAIL. (т.к. нормально обменивает только числа в половину разрядности long'а).

      P.S. Но реализация понравилась, такого извращения для обмена переменных я еще не видел, поэтому ловите плюс.
      Ответить
      • > long a=22807;
        > long b=1012;
        Автора сгубило неумение писать юнит-тесты
        Ответить
        • > Автора сгубило неумение писать юнит-тесты
          Что вы, это наоборот умение "как составить тесты для неработоспособной программы, чтобы сдать ее неопытному заказчику".
          Ответить
        • Что то такое?

          long long int a=-41000L;
          long long int b=-5305L;
          for(long i=0;i<=1000000L;i++){
          printf("before a=%lld b=%lld\n",a,b);
          swap(&a,&b);
          printf("after a=%lld b=%lld\n",a,b);
          swap(&a,&b);
          printf("a=%ld b=%ld\n",a,b);
          a++;b++;
          }
          Ответить
          • > long long int;
            Тогда, чтобы быть честным, запилите цикл до 4000000000 (можно с большим шагом). Баг с потерей старших разрядов один хрен не устранен.

            > printf("after a=%lld b=%lld\n",a,b);
            Юнит-тест не должен лишний раз показывать промежуточные результаты (разве что если найдет ошибку), а должен показывать результат теста - успех или ошибку. К примеру:
            long long tmpa = a, tmpb = b;
            swap(tmpa, tmpb);
            if (tmpa != b || tmpb != a) {
                printf("Test failed on a=%lld b=%lld\n", a, b);
                return 1;
            }
            Ответить
    • Знак теряется если одна <0, то вычитается из числа
      более правильно
      #include <stdio.h>

      void swap(int *a,int *b){
      if(*a<0 & *b<0){
      *a*=-1;*b*=-1;
      *a=(*a<<sizeof(*a)*4);
      *a+=*b;
      *b=*a ^ *b;
      *b=(*b>>sizeof(*a)*4);
      *a=(*a<<sizeof(*a)*4);
      *a=(*a>>sizeof(*a)*4);
      *a*=-1;*b*=-1;
      } else if(*a<0){
      *a*=-1;
      *a=(*a<<sizeof(*a)*4);
      *a+=*b;
      *b=*a ^ *b;
      *b=(*b>>sizeof(*a)*4);
      *a=(*a<<sizeof(*a)*4);
      *a=(*a>>sizeof(*a)*4);
      *b*=-1;
      } else if(*b<0){
      *b*=-1;
      *a=(*a<<sizeof(*a)*4);
      *a+=*b;
      *b=*a ^ *b;
      *b=(*b>>sizeof(*a)*4);
      *a=(*a<<sizeof(*a)*4);
      *a=(*a>>sizeof(*a)*4);
      *a*=-1;
      } else {
      *a=(*a<<sizeof(*a)*4);
      *a+=*b;
      *b=*a ^ *b;
      *b=(*b>>sizeof(*a)*4);
      *a=(*a<<sizeof(*a)*4);
      *a=(*a>>sizeof(*a)*4);
      }
      }
      Ответить
      • > Знак теряется
        Да тут не только знак, тут в строке 4 половина разрядов числа a втопку уходит: *a=(*a<<sizeof(*a)*4). Новый вариант в этом плане ничуть не лучше.

        > *a*=-1
        Красота ;)
        Ответить
        • Its need to use long long int type
          Ответить
          • long long long long long long long long long long long long long ...
            Ответить
          • А вот такой код не требует, и работает на полную разрядность переменных:
            *a ^= *b;
            *b ^= *a;
            *a ^= *b;
            Ответить
            • *a^=*b^=*a^=*b
              Ответить
              • UB?
                Ответить
              • Фу-у. Так оно даже не будет работать в языках с нормальным приоритетом.
                tmp1 = a; 
                 tmp2 = b;
                 tmp3 = a ^ b;	//=a^b
                a = tmp3;	//=a^b
                b = tmp2 ^ tmp3;//=(b) ^ (a^b) =a
                a = tmp1 ^ b; 	//=a^a=0

                Рекомендую сравнить по количеству действий с тем как пишут "тупые", неилитарные кодеры.
                tmp = a;
                a=b;
                b=tmp;
                Ответить
                • > как пишут "тупые", неилитарные кодеры
                  А "умные" неилитарные кодеры пишут swap(a, b)
                  Ответить
                  • (a,b)=(b,a)
                    a <-> b
                    Ответить
                    • > a <-> b
                      Что-то запамятовал, это какой язык?
                      Ответить
                      • nemerle небось
                        Ответить
                        • Nemerle, ага. Самое бесполезное, что есть в Немерле. Но таки в этом действительно всех уделал по интуитивности и краткости.
                          Ответить
                      • Это какой-то выдуманный сверхлаконичный язык был, весёлая тема была на рдсн.
                        Чувак показал пример сортировки пузырьком на своём языке:
                        a[i]>a[j]?a[i]:=:a[j]

                        правда неоднозначность семантики выяснилась слишком быстро.
                        Ответить
                        • using System.Console;
                          mutable a=10;
                          mutable b=20;
                          WriteLine("{0},{1}",a,b);
                          a <-> b;
                          WriteLine("{0},{1}",a,b);

                          http://ideone.com/jJswF
                          Ответить
                • Фууу, тмп, это же так по-ламерски. Настоящий кулхацкер, знающий железо, никогда так не напишет.
                  Ответить
                  • register auto tmp = a;
                    a=b;
                    b=tmp;
                    Ответить
                    • на register компилятор, насколько я помню, давно уже плюет с высокой колокольни.
                      а с auto тоже смысл изменился из C++0x.
                      Ответить
                      • >а с auto тоже смысл изменился из C++0x.
                        Если вы не заметили, то этот новый смысл как раз применяется.

                        >на register компилятор, насколько я помню, давно уже плюет с высокой колокольни.
                        Эх, надо было мне код зеленым оборачивать.
                        Ответить
                    • Кстати, я уже было подумал, что я соснулей со ссылками (но нет):
                      http://ideone.com/DzIRA
                      Ответить
            • Только почему-то никто никогда не говорит, что этот "умный" код полное говно. Потому что оно медленее чем обычная перестановка с лишней переменной.
              Даже в былые времена когда регистров было мало, это считалось сомнительным ибо существовал XCHG.
              Ответить
              • > это считалось сомнительным
                Это же просто головоломка. Зачем к ней так серьезно подходить?

                P.S. То что говно - да. И к тому же (по крайней мере на x86) компилятор запилит временную переменную в регистре (если сами a и b не в регистрах), т.к. на x86 нельзя выполнять операции над двумя областями памяти одной командой.
                Ответить
                • Если a и b оказались в памяти какого-то хера, то палюбэ пизда скорости, и да, сишкобляская передача по указателю способствует.
                  А если они в регистрах, то обмен скорее всего будет в 3 действия через третий регистр.
                  Ответить
                  • Я не о скорости, я о том что сишкоблядский некристекомпилятор может нарушить условие задачи, создав временную переменную, тем самым поставив данное решение под сомнение.
                    Ответить
          • And I think it's gonna be a long long time.
            Ответить
          • long long ago; //in a galaxy far far away...
            Ответить
    • Вызвало ассоциации с наряженной елкой.. наверно программист спешил домой 31 декабря =)
      Ответить

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