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

    +15

    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
    #include <iostream>
    #include <functional>
     
    template<class Container, class F, class A>
    auto accumulate(Container c, F f, A acc) -> A
    {
      auto id = [](const A& a) -> const A& {return a;};
      typedef decltype(std::begin(c)) Iterator;
      const std::function<A(const Iterator& lst, const std::function<A(const A&)>&)> doIt = 
      [&](const Iterator& lst, const std::function<A(const A&)>& cont) -> A
      {
        if(lst==c.end())
          return cont(acc);
        else
        {
          auto conter=[&](const A& acc) -> A {return cont(f(*lst, acc));};
          return doIt(lst+1, conter);
        }
      };
      return doIt(std::begin(c), id);
    }
     
    int main() {
            std::cout<<accumulate({1,2,3,4}, std::plus<int>(), 0);
            return 0;
    }

    Похоже написал какой-то монадолог.
    http://ideone.com/y4Dm9z
    Пример использования accumulate сам накатал.
    Я побаловался с этим примером, чтобы разобраться и GCC ожидаемо упал:
    http://ideone.com/XWfuoP
    Я убежден, что эта функция должна была выглядеть как-то так:

    template<class Container, class F>
    accumulate(const Container& c, const F& f=std::plus<decltype(*(std::begin(c)))>(), const decltype(*(std::begin(c))) acc=decltype(*(std::begin(c)))()) -> decltype(*(std::begin(c)))
    {
    return std::accumulate(c.begin(), c.end(), acc, f);
    }
    //Вызов этой функции:
    accumulate({1,2,3,4});

    Ну и я погуглил на тему этого говнокода и нашел на функциональном языке похожий:
    let fold_right func acc list =
    let rec loop list cont = //сюда мы передаем текущую функцию континуации
    match list with
    |[] -> cont acc //а вот и наше ключевое вычисление.
    |head::tail -> loop tail (fun racc -> cont (func head racc))
    loop list (fun x -> x)

    Запостил: LispGovno, 23 Ноября 2012

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

    • Перед accumulate auto забыл:
      template<class Container, class F>
      auto accumulate(
      Ответить
    • Вообще в этом треде я особого говна то и не вижу, но у accumulate(Container c, F f, A acc) -> A акамулятор, функтор, а самое главное контейнер копируется по значению. Автор норкаман
      Ответить
    • Ах да, подход называется котоморфизм (можите загуглить) - изменение кота.
      Ответить
      • А ещё заметьте. Рекурсия то хвостовая, а дополнительный параметер под аккумулятор вводить не пришлось. Не знаю что со мной, но я начинаю симпатизировать этому решению.
        Ответить
    • почему некоторые питушки пишут так не читабильно?
      Ответить
    • Парень, я партизаню тут довольно давно, и вот: у тебя КРЕСТОПРОБЛЕМЫ
      Ответить
      • Какие крестопроблемы блеать? Авторкода еблан и это все объясняет.
        Ответить
        • > Какие крестопроблемы блеать? Авторкода еблан и это все объясняет.
          КРЕСТОБАТХЁРТ
          Ответить
          • это ты от того гостя писал? какой может быть батхерт, если некий функциональщик решил в кресты перетащить функцианальщину. а анальщиной занимаются только пидарасы
            Ответить
    • Здесь есть люди, хорошо знающие кресты? Вот я выбираю между 80битном long double и 64xbit double для вычислений. Мне важна скорость. Что мне лучше выбрать? Точности 32хбитного float не хватает.
      Ответить
      • Имхо 64 битный, т.к. во-первых компилятор может применить для него SSE (а то же сравнение на SSE намного короче и быстрее). Во-вторых у него лучше выравнивание.
        Ответить
        • Нет, SSE не допустим в рамках задачи. Только FPU.
          Вообще как сейчас у современных процессоров с производительностью FPU и связь производительности с точностью и как с этим было раньше? У меня очень широкий парк машин. От самых современных до 486. И на всех это должно работать.
          Что посоветуете? 64 или 80?
          Ответить
          • НЕ long double.

            Некторые компиляторы могут трактовать его либо как "80-bit extended precision" либо как "128-bit quadruple precision". Понятно что скорости это не прибавит. На PowerPC с gcc этот тип будет в итоге "double-double" (128 бит, но с другим соотношением бит в мантиссе/экспоненте).

            Так что, лучше отказатья от него и использовать double.

            Также многие компиляторы (например интеловский) считают простой double вещественным с расширенной точностью (80-бит). Так-что возможно разницы вообще не будет.

            А также:
            можно провести объективный тест с передачей в функции, сложением, умножением и выбрать то, что будет быстрее.
            Ответить
            • Среди платформ, для которых нужна эта программа будут только потомки х86, даже х64 не будет. Среди компиляторов только студии, так что насчет лонг дабл - 80 и double - 64 -- я не ошибся
              Ответить
            • > объективный тест
              http://govnokod.ru/12180#comment162162
              Ответить
              • Написал говнотест:
                http://ideone.com/rlTw1w

                Сам удивился результатам.

                1. Нет ощутимой разницы между float и double.
                2. Совсем небольшое различие между double и long double.
                3. sizeof(long double) == 12! (96 бит)
                Ответить
                • А что удивляться, сами вычисления всегда идут в 80битном режиме (если компилятор не поюзает 32 и 64 битные числа через SSE). Так что разница тут будет только во времени сохранения в память и загрузки из нее.

                  > sizeof(long double) == 12
                  Для выравнивания на 4 байта. Заполняться будут первые 10, в остальных окажется мусор.
                  Ответить
                  • > Сам удивился результатам.
                    > А что удивляться

                    Ты убиваешь всю магию.
                    Ответить
                • UPD: режим вычислений можно переключать в control word сопроцессора (single/double/extended), но компилятор этого делать скорее всего не будет, т.к. частые переключения тоже ухудшат производительность.

                  Да и бонус можно получить только на джвух операциях - делении и корне. Говорят, что всякие синусы\косинусы от этого не ускоряются.
                  Ответить
                • тест реально говно
                  на -O2 компилятор выкидывает практически все, что ты понаписал (см gcc.godbolt.org)
                  void fractionalTest<float>():
                  	rep
                  	ret
                  void fractionalTest<double>():
                  	rep
                  	ret
                  void fractionalTest<long double>():
                  	rep
                  	ret
                  Ответить
      • double же.
        Ответить
        • бенчи же
          Ответить
          • SSE же
            Ответить
            • Не факт, что компилятор поюзает SSE.
              Ответить
              • Ассемблерные вставки отменяются?
                Ответить
              • вот такая херня на -O2 засчитывается, как sse?
                void fractionalTest<double>(double, double):
                	ucomisd	xmm0, xmm1
                	mov	eax, 1
                	jp	.L7
                	jne	.L7
                .L6:
                	movsd	xmm2, QWORD PTR .LC2[rip]
                	xor	edx, edx
                	ucomisd	xmm1, xmm0
                	addsd	xmm0, xmm2
                	subsd	xmm1, xmm2
                	seta	dl
                	add	eax, edx
                	add	DWORD PTR void fractionalTest<double>(double, double)::int_accum[rip], eax
                	movapd	xmm2, xmm0
                ....
                Ответить
    • просто вернись обратно на свои говноборды
      Ответить

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