Как стать автором
Обновить

Комментарии 47

Комментарии к коммитам на русском — это конечно сильно)
Очень круто. Как будто какой-нибудь ФП-шный хаскелевский Data.List в C++ перетащили. Надо добавить в Boost. Правда от 90% до 99% программистов все-равно будут у себя писать циклы по-старинке, максимум — с использованием известных функций STL.

Спасибо :) .

Скажите, а если ядро свёртки ассоциативно, я могу как-то распараллелить не промежуточные операции, а итоговую свёртку? Ну, чтобы разбить исходную последовательность на несколько кусков и каждый кусок обрабатывать на своём потоке.

Отмечу, что это позволит нормально использовать кэш процессора, что в отдельных случаях приводит к ускорению кода на 2 порядка.


Было бы интересно посмотреть на замеры скорости cache-friendly цикла и этого решения.

Спасибо за вопрос. В текущей версии нет, но вообще, конечно, да. Просто пока не было времени реализовать. Если есть желание и возможность, с радостью приму помощь.

Привлекли термины попавшие в заголовок статьи «циклы», «алгоритмы». Традиционно именно циклы используют в алгоритмах сортировки массивов. Можно пример «простой» сортировки (вставка, пузырек, выбор...), алгоритм которой должен состоять из двух циклов. Не хочу никого обижать, но действительно, очень желал бы увидеть, какой это будет «красивый, понятный, эффективный код». Только в рекурсивном выражении не нужно, в этой формулировке Эрланг уже получил приз за высокую «красивость и неэффективность», там вот одной строки хватает:
q([])->[];q([H|T])->[q([X<-T,X=<H])]++[H|q([X<-T,X>H])].

upd: даже раскраска исходного текста не выдержала, только первый символ смогла отделить, ха-ха, похоже, её реализовал тот, кто умеет красиво и эффективно одновременно.
upd2: почему только первый идентификатор функции выделяет цветом, почему далее по тексту, три раза встречается «кюю» и почему оно не выделилось…, а если вводить с новой строки — то сработает, получается лексемы не верно выделяет, парсер какой-то «левый»:
q([])->[];
q([H|T])->[q([X<-T,X=<H])]++[H|q([X<-T,X>H])].

upd3: как так, почему на профильном сайте такая ситуация, отмечаю текст необходимым языком, а это приводит к созданию картины неясности и недопонимания конструкций этого языка, а в дальнейшем это приводит к исключении его из списка языков, так уже Пролог «почил» уже более года назад, лично отмечено…
upd4: ну и на последок, а что показывает «индустрия», как это будет выглядеть в другом стиле:
q([])->[];q([H|T])->[q([X<-T,X=<H])]++[H|q([X<-T,X>H])].

на профильном сайте страничка с тысячью комментариями жрёт ресурсов больше чем современные компьютерные игры, а вы тут про расскрасски :)

Не, думаю там виной вселенский заговор, это Хром занимает все ресурсы драйверами всех типов видеокамер, что бы следить за человечеством в пользу Гугла.
Вот именно. Нормальный браузер весь целиком, вместе со страничкой,
потребляет порядка 23 Мб

И это с прогрузкой графики и форматированием. Чисто текстовые браузеры жрали бы ещё меньше.
Я Нелениво выполнил вручную итерации цикла и получил такую композицию
уменьшая влияние проблем в раскраске синтаксиса на суть:
qsort( X ) when X = [] -> []; 
qsort( [H | T] ) - >
         L = qsort([X || X <-T , X<H]),
         R = qsort([X || X <-T , X>=H]),
         L ++ [H] ++ R.

сверху все примеры с опечаткой были, тут устранено

Прям Matlab, как-то написал в стиле без циклов прототип в матлабе, а потом понял что релиз то на си надо >.<

Циклы ужасны. Циклы сложно читать — вместо того, чтобы сразу понять намерение автора, приходится сначала вникать в код, чтобы понять, что именно он делает. В цикле легко ошибиться с индексированием и переопределить индекс цикла во вложенном цикле. Циклы сложно поддерживать, исправлять в случае ошибок, сложно вносить текущие изменения, и т.д. и т.п.

С++ ужасны. С++ сложно читать — вместо того, чтобы сразу понять намерение автора, приходится сначала вникать в код, чтобы понять, что именно он делает. В С++ легко ошибиться. С++ сложно поддерживать, исправлять в случае ошибок, сложно вносить текущие изменения, и т.д. и т.п.

Можно подставить что угодно. Где доказательства? Чем обоснованы эти утверждения?
Если автор не умеет понятно писать, язык программирования тут не причем. А избавлять императивный язык от циклов затея бестолковая. Если у вас высокоуровневый код то там циклов почти нет. А в низкоуровневом они никому не мешают и таскать туда STL,Boost,range-v3 и другие велосипеды не всегда хорошая идея.

Если вы хотите строить вычислительный граф и потом его преобразовывать и объединять с другими графами и искать оптимальный, то это надо делать до компиляции. В C++ нет встроенных средств языка для преобразования вычислительных графов. А предложение использовать убогий препроцессор и новые марсианские фичи С++ для данной задачи и потом надеяться что он всё оптимизирует говоря не дальновидно. Не надо смешивать всё в кучу ибо сложность будет нарастать экспоненциально. И проблем будет создано больше чем решено. Лучше разбить на отдельные простые части и есть слона по частям.
Что мешает вызывать из высокоуровневого кода черный ящик, оптимизированный под конкретную железяку.

ps: «Человечество издревле пытается упростить написание циклов» — первый раз слышу что бы это было важнее свежей тротуарной плитки.
Если автор не умеет понятно писать

Это можно легко проверить, заглянув в репозиторий.


избавлять императивный язык от циклов затея бестолковая

C++ — мультипарадигменный язык.


это надо делать до компиляции

Где доказательства? Чем обоснованы эти утверждения?
;)


ps

Я не могу к каждой шутливой фразе делать сноску "юмор".

НЛО прилетело и опубликовало эту надпись здесь
почти все реальные вычислительные алгоритмы (а это именно то, что загружает процессоры) написаны на фортране

А какая доля этих программ написана в этом веке?

НЛО прилетело и опубликовало эту надпись здесь
Встречный вопрос — а какая доля программ написана на ЯП, первая версия которого появилась в 1985 году, до 1970 года и до сих пор используются?

Уточнил вопрос.

Описанная Вами практика общепризнанно является порочной. Использование goto в Фортране не требуется и порицается еще с момента выхода стандарта 90 в 91-м году, то есть уже на протяжении 30-и лет. Актуальных программ, где "кроме цикла и goto особо ничего и не используется", почти не осталось — все переписано или переписываются на соврмененный стандарт Фортрана или C++ по очень многим причинам, в том числе сходным с отмеченными автором.
Кроме того, высокопроизводительное вычислительное ПО сейчас — это далеко не только, и даже, к моему сожалению, не столько Фортран, это еще C или C++, а иногда смесь Фортрана и C++.

НЛО прилетело и опубликовало эту надпись здесь

На Ваш первый вопрос мне трудно дать исчерпывающий ответ. Скажу, что никогда не встречал ни одной рекомендации в духе: "используйте goto вместо if-then-else". Управлаемый goto в последней редакции стандарта официально вынесен в список устаревших конструкций, подлежащих удалению из стандарта.


Использовать goto не нужно тогда, когда для этого нет причин.

Его активное использование плохо тем, что запутывает код для восприятия и программистом, что усложняет развитие кода, и компилятором, который в таких случаях избегает применения оптимизаций. С другой стороны, в подавляющем большинстве случаев явные конструкции if-then-else, do, do while с exit и cycle абсолютно ничем не уступают goto, но они гораздо более выразительны. Хотя я могу себе представить алгоритмы, где использование goto может принести выгоду, это, все-таки, скорее исключение, и почти всегда goto если используется, то именно вместо указанных выше стандартных конструкций.


И в целом, не видел я ни одной серьезной программы на Фортране с goto, common-областями, процедурами по 1000 строк с именами длиной 5 символов (это все составляющие одного и того же стиля), без сомнения написанной программистами с высокими представлениями о своих умственных способностях, в которой не нашлось бы банальных (и, вообще-то, серьезных) ошибок с памятью. Просто потому, что все программисты — люди, а люди ошибаются. Использование наделенных абстрактным смыслом избыточных, но выразительных, конструкций сродни такой культуре и позволяет обнаружить многие ошибки еще на этапе компиляции, а не через два года эксплуатации. А это особенно важно именно в численных методах.


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


Про MKL пишут, что она на писана на "C/C++, Fortran". Фортрановская часть кода MKL никак не обосновывает разработку новых программ теми же методами.


На C++ написана куча вычислительных программ. Тот же GEANT4, который переписан с Фортрана еще в 90-х для того, чтобы развиваться. Вообще, с Фортрана, к сожалению, уходят, на C++, текущий пример.
Писать интерфейсы вычислительных программ на C++ сейчас особого смысла нет — есть методы проще и эффективнее.

Вообще свежиё фортран вполне неплохой язык, пусть лично для меня менее комфортный, чем матлаб или питон, ну и нативную многопоточность в него завезли одного из первых.

Если получается решать задачи на Питоне, то Фортран там скорее всего не сильно и нужен, так как будет больше ограничений и меньше библиотек. Фортран ближе к железу: например, сечения массивов в Питоне — это скорее синтаксический сахар, а они же в Фортране — почти прямое указание компилятору использовать SIMD-инструкции для векторизации.
Фортран лучше подходит для разработки сложных программ, жизненный цикл которых измеряется десятилетиями, а там основной выбор лежит между Фортраном и C/C++.

> Управлаемый goto в последней редакции стандарта официально вынесен в список устаревших конструкций, подлежащих удалению из стандарта.

Простите, а при чём тут computed GOTO к общей теме поддержки GOTO? Или что-то после N2146 публично доступно и говорит про устаревание простого GOTO?
(Я тоже за то, чтобы вместо GOTO использовать почти везде структурные конструкции, но именно этот момент смущает.)

> Но ассоциации с «фишками» Фортрана-77 приводят к неуклонному снижению его популярности.

77 уже был продвижением вперёд — как классика вспоминается IV или 66 :)
Простите, а при чём тут computed GOTO к общей теме поддержки GOTO? Или что-то после N2146 публично доступно и говорит про устаревание простого GOTO?

Пишу про парадигму и стиль программирования. Речь шла о "кроме цикла и goto особо ничего и не используется". Управляемый goto, просто goto, имена подпрограмм по 4-6 символов, и даже размножение фрагмента кода с заменой имен переменных и одной строки — все это обычно идет в одном комплекте.
Про вывод самого goto из стандарта не слышал, и думаю, что вряд ли это произойдет.


77 уже был продвижением вперёд — как классика вспоминается IV или 66 :)

Согласен. Уже в этом стандарте постоянное использование goto было не обязательно. Но, к сожалению, в моей среде многие его новшества были прогнорированы, кроме, разве что, оператора include.


Возможно, в корне этого спора лежит различие подразумеваемых областей применения. Использование обсуждаемых приемов программирования в библиотеке для операций с двумя матрицами, реализованной "раз и навсегда", наверное, не так критично.

> И хотя я знаю, откуда пошло это клеймение goto, ни я, ни многие другие программисты не понимают, чем плох goto, а теперь уже и циклы… Видимо, это связано с ослаблением умственных способностей программистов, не в обиду будь сказано.

Когда считалось нормой задумчиво сидеть с ручкой над листингами и выдавать как результат 1 отлаженную строку кода за рабочий день… ну может тогда и можно было тратить умственные способности на плоскую плетёнку с GOTO, и даже допускать приёмчики типа прыжка из середины одного цикла в середину другого цикла (видел я как-то в юности такой код и впечатлён до сих пор).

Но уже в начале-середине 80-х стали запрещать (в разумных пределах) эти фокусы — в середину цикла, например, вы так уже не перейдёте. Разумеется, сохраняется возможность эмулировать циклы, структурный IF и прочее на сплошных GOTO — но зачем?
а куда стоит податься, если не до конца понимаешь потенциал всего описанного?

Ну, наверное, можно пройтись по ссылкам в конце статьи.
Или задать какой-нибудь конкретный вопрос, я постараюсь ответить.

Можете посоветовать книжку-учебник по плюсам 17/20 стандартов? Я учил по книжке Страуструпа и какому-то этюднику для 03, и даже тогда плюсы были очень рыхлыми. Я сейчас из всех «свежих» плюсов более-менее понимаю только шаблоны :) Понятно, что прочесть сниппет могу, но вот код писать не возьмусь.
C++17 — The Complete Guide
по 20му едва ли уже успели написать что-то стоящее

Не думаю, что по 17-м плюсам необходим отдельный учебник.
Если нужно просто понять суть современных плюсов, то вполне достаточно последней редакции Страуструпа (она включает 14-й стандарт).
Также можно почитать Майерса — "Эффективный современный C++".


Вот про 20-й было бы неплохо отдельную книжку иметь, но мне такие неизвестны.

так он только только вышел же
Jens Gustedt умудряется писать маны для ещё не вышедшего стандарта С. Правда, он в комитете.
по 20му стандарту тоже были маны по принятым преложениям или тому что еще рассматривается, там ведь не за одну встречу принимают весь стандарт, но книги из серии «стандарт еще вышел, и половина рассказаного еще не принята» у меня лично вызывает вопрос «зачем?», зачем было писать книгу о стандарте если он не закончен на момент выхода книги

Недавно вышел именно учебник, "Modern C++ for Absolute Beginners" (подзаголовок: "A Friendly Introduction to C++ Programming Language and C++11 to C++20 Standards"), Slobodan Dmitrović. Есть ещё пара недавних книг (не учебников), в которые я заглядывал: "Modern C++ Tutorial: C++11/14/17/20 On the Fly", Changkun Ou и "C++ Best Practices", Jason Turner. От комментариев, что в этих книгах хорошо / плохо воздержусь, заглядывал только поверхностно. Возможно, стоит обратить внимание на вышедшее летом 2018-го второе издание "A Tour of C++ (C++ In-Depth Series)", Bjarne Stroustrup.

Спасибо. Это было внезапно :)

Зашёл на эту запись по ассоциации, прочитав свежий пост izvolov -а.


Да и книги вышли внезапно, относительно недавно. Я узнал о двух из них, слушая подкаст "CppCast", Jason Turner — его соведущий. С Слободаном у них был выпуск (Джейсон как раз свою книгу писал тогда, расспрашивал Слободана), а потом о выходе книги Джейсона упомянули между делом. Книга Чангкуна не такая новая; она в свободном доступе (на Гитхабе) и, вероятно, обновляется.


Ожидаю, что в ближайшее время появится несколько новых редакций книг, в названии которых "C++17" будет заменено на "C++20": тот же эффект, как три года назад (когда в названии ставили C++17). Я тогда тоже поверхностно пролистал несколько книг, но не был впечатлён (попадалась откровенная халтура).

Спасибо, интересно! А как со длительностью компиляции обстоят дела у вашей библиотеки? Оригинальные ranges Ниблера компилируются прям ооочень долго (вроде бы в основном из-за самодельных концептов).

Довольно шустро, хотя специальных замеров не делал. С Ниблером несопоставимо :) .

Здорово!

Еще такой вопрос, не про библиотеку, а скорее про свертки.
Может быть у меня мозги не обучены еще в таких понятиях думать, но мне все время кажется, что свертки хорошо смотрятся, если цикл:


  • по всей коллекции целиком
  • затрагивает либо каждый элемент по отдельности, либо только соседние элементы, либо элементы, подчиняющиеся какому-то паттерну
  • не удаляет элементы

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

удалить третий, пятый и 19-ый элемент

Никаких проблем. Можем сделать преобразователь, удаляющий n-й элемент по счёту, и собрать из них любую схему удалений.


начав проход со второго, а закончив на 3 элемента раньше конца

Границы удобнее задавать итераторами, но тоже можно, если хочется.


const auto result =
    proxima::reduce(items.begin() + 2, items.end() - 3,
        proxima::compose
        (
            drop_nth(3),
            drop_nth(5),
            drop_nth(19),
            proxima::sum
        ));

А drop_nth не сбивает нумерацию?

Смотря как сделать :).
Можно сделать сбивающим, но многопозиционным:


const auto result =
    proxima::reduce(items.begin() + 2, items.end() - 3,
        proxima::compose
        (
            drop_nth(3, 5, 19),
            proxima::sum
        ));

Уболтали :) Спасибо!

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

Можете пояснить про недостатки итераторов? И как понять "отделены от схемы вычислений"?

В данном случае речь идёт о том, что итератор определяет обход последовательности и выдачу элементов.
При этом итератор не знает, что будут делать с выданными им элементами: умножать, складывать, что-то ещё.


Из проблем, навскидку:


  • Неочевидные просадки по производительности в простых случаях (например, если поставить filter после transform, который читает из файла или делает что-то долгое). При этом код корректен, компилируется и работает.
  • Накладные расходы на хранение данных в сложных итераторах (например, чтобы решить предыдущую проблему, можно создать итератор, который будет кэшировать промежуточные вычисления. Но чтобы это засунуть в итератор, потребуется завернуть кэш во что-то типа shared_ptr, а это уже лишний уровень косвенности.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории