Комментарии 47
Скажите, а если ядро свёртки ассоциативно, я могу как-то распараллелить не промежуточные операции, а итоговую свёртку? Ну, чтобы разбить исходную последовательность на несколько кусков и каждый кусок обрабатывать на своём потоке.
Отмечу, что это позволит нормально использовать кэш процессора, что в отдельных случаях приводит к ускорению кода на 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])].
на профильном сайте страничка с тысячью комментариями жрёт ресурсов больше чем современные компьютерные игры, а вы тут про расскрасски :)
уменьшая влияние проблем в раскраске синтаксиса на суть:
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
Я не могу к каждой шутливой фразе делать сноску "юмор".
почти все реальные вычислительные алгоритмы (а это именно то, что загружает процессоры) написаны на фортране
А какая доля этих программ написана в этом веке?
Описанная Вами практика общепризнанно является порочной. Использование goto в Фортране не требуется и порицается еще с момента выхода стандарта 90 в 91-м году, то есть уже на протяжении 30-и лет. Актуальных программ, где "кроме цикла и goto особо ничего и не используется", почти не осталось — все переписано или переписываются на соврмененный стандарт Фортрана или C++ по очень многим причинам, в том числе сходным с отмеченными автором.
Кроме того, высокопроизводительное вычислительное ПО сейчас — это далеко не только, и даже, к моему сожалению, не столько Фортран, это еще C или C++, а иногда смесь Фортрана и C++.
На Ваш первый вопрос мне трудно дать исчерпывающий ответ. Скажу, что никогда не встречал ни одной рекомендации в духе: "используйте goto вместо if-then-else". Управлаемый 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++.
Простите, а при чём тут 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.
Возможно, в корне этого спора лежит различие подразумеваемых областей применения. Использование обсуждаемых приемов программирования в библиотеке для операций с двумя матрицами, реализованной "раз и навсегда", наверное, не так критично.
Когда считалось нормой задумчиво сидеть с ручкой над листингами и выдавать как результат 1 отлаженную строку кода за рабочий день… ну может тогда и можно было тратить умственные способности на плоскую плетёнку с GOTO, и даже допускать приёмчики типа прыжка из середины одного цикла в середину другого цикла (видел я как-то в юности такой код и впечатлён до сих пор).
Но уже в начале-середине 80-х стали запрещать (в разумных пределах) эти фокусы — в середину цикла, например, вы так уже не перейдёте. Разумеется, сохраняется возможность эмулировать циклы, структурный IF и прочее на сплошных GOTO — но зачем?
Ну, наверное, можно пройтись по ссылкам в конце статьи.
Или задать какой-нибудь конкретный вопрос, я постараюсь ответить.
по 20му едва ли уже успели написать что-то стоящее
Не думаю, что по 17-м плюсам необходим отдельный учебник.
Если нужно просто понять суть современных плюсов, то вполне достаточно последней редакции Страуструпа (она включает 14-й стандарт).
Также можно почитать Майерса — "Эффективный современный C++".
Вот про 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
));
Ленивые итераторы и диапазоны решают многие проблемы. Но они сами не лишены своих собственных проблем. В частности, поскольку они отделены от схемы вычислений (они определяют только операции над отдельными элементами последовательности), их сложно параллелить.
Можете пояснить про недостатки итераторов? И как понять "отделены от схемы вычислений"?
В данном случае речь идёт о том, что итератор определяет обход последовательности и выдачу элементов.
При этом итератор не знает, что будут делать с выданными им элементами: умножать, складывать, что-то ещё.
Из проблем, навскидку:
- Неочевидные просадки по производительности в простых случаях (например, если поставить
filter
послеtransform
, который читает из файла или делает что-то долгое). При этом код корректен, компилируется и работает. - Накладные расходы на хранение данных в сложных итераторах (например, чтобы решить предыдущую проблему, можно создать итератор, который будет кэшировать промежуточные вычисления. Но чтобы это засунуть в итератор, потребуется завернуть кэш во что-то типа
shared_ptr
, а это уже лишний уровень косвенности.
Долой циклы, или Неленивая композиция алгоритмов в C++