Pull to refresh
4
0
Send message

Между прочим, неплохая тема для школьного математического кружка (и я проводил такое занятие один раз, лет 20 назад, кажется, взяв идею из старой советской книги, там были цыплята :) ), поскольку решаемая в конце задача на экстремум может быть разобрана без производных - на уровне квадратных уравнений или неравенства о среднем арифметическом и среднем геометрическом. У вас небольшая опечатка в "... ½С1∙T∙q+RСs/q. После дифференцирования по q находим ½С1∙T+RСs/q2" - конечно, после дифференцирования между слагаемыми минус, а не плюс!

Хорошее объяснение, спасибо!

Изящное и, по-моему, правильное решение, не вижу изъянов - лучший комментарий здесь (я, правда, пролистал бегло)! Бонус - очевидная линейная асимптотика в результирующей компактной формуле (автор заметки упоминает этот аспект, хорошо понятный при "физическом" рассмотрении того, что происходит при масштабировании N, например, рассмотрении испытания с 2N шарами как двух испытаний с N шарами).

Меня этот вывод от pavelgein не убеждает (наоборот, вижу путаницу в определениях случайных величин, а "догадаться, что хотел сказать автор, но оговорился" нет времени, желания), а вот разбор от Pavgran ниже по комментарием выглядит корректно, плюс, в результате - компактная формула с очевидной линейной асимптотикой. Кстати, догадка о линейности асимптотики - довольно "физическая", можно рассматривать, как ведёт себя величина при возрастании N вдвое при больших значениях N - разделив испытание с 2N шарами на комбинацию двух испытаний с N шарами. При больших N одной возможной серией белых шаров, продолжающейся с первого N-испытания на второе можно пренебречь, посчитав её два раза - линейность тогда становится наглядной (что не умаляет необходимости доказать её строго, с формулой от Pavgran).

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

Автор ничего не упрощал (у вас, может быть, есть на руках более сложный пример, который автор упростил?), он предоставил относительно простую демонстрацию возможной обвязки без многопоточности. Сопрограммы хорошо работают с многопоточностью, но могут быть использованы и в простом однопоточном контексте, как представлено здесь. И так уже нужно довольно повозиться. Я этим занимался, теперь (на другом проекте) не хочу торопиться -- к сожалению, стандартная библиотека не включает удобную поддержку в C++20.

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

Понятно, спасибо! У меня сложилось мнение, что эту языковую возможность (виртуальное наследование) скорее принято обходить (не в последнюю очередь - из-за сложного лэйаута объектов и дополнительного кода, генерируемого компилятором для доступа из объекта-наследника к базовому объекту, наследованному веритуально). Сам за годы программирования на C++ использовал, наверно, пару раз (причем первый раз - в самом начале карьеры, было интересно освоить эту возможность языка - сейчас бы скомпоновал тот код по-другому).

Спасибо, интересно. Скажите пожалуйста, почему наследование от базового класса Turn - виртуальное? Все классы-наследники финальны, проблемы ромба не возникает. Таким образом, объявляя базовый класс виртуальным базовым классом вы платите за то, что вам не нужно в этом проекте. Других случаев наследования в хедерах я не нашёл, бегло просмотрев, и предполагаю, что это - следствие какого-то внешнего влияния (так принято наследовать в Qt?).

Ссылка по теме вопроса:
https://en.wikipedia.org/wiki/Virtual_inheritance

Good to know, thanks — looks like i was fooled by a random "tutorial" page that pops up in search results at the top.

Посмотрите на https://github.com/Ludeme/Ludii — недавно выложенный на Гитхабе исходный код активного проекта по теме с довольно длинной историей.

Отлично! У меня (пишу на C++ на работе) под рукой пара рекомендаций (я сам стараюсь быть в курсе развития языка, хотя именно на работе далеко не всегда имеется возможность применить те или иные улучшения):


https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines — живой, развивающийся документ, рекомендации от ведущих специалистов комитета стандартизации.


https://github.com/changkun/modern-cpp-tutorial — учебник по основным новым фичам, появившимся в последних 4-х итерациях стандарта.


Есть пара очень недавно вышедших книг (у одной автор Slobodan Dmitrović, у другой Jason Turner), не могу уверенно рекомендовать, так как сам не прочитал, листал только.


Оговорюсь, что может показаться, что стремление использовать новые возможности языка — сходна к желанию поиграть в новые блестящие игрушки. Это не совсем так! Изменения и нововведения делаются для решения определённых проблем, они действительно полезны в долгосрочной перспективе. Документ Cpp Core Guidelines иногда объясняет смысл нововведений, я часто в него заглядываю по практической нужде.

Болат, зачем вам вспоминать такой C/C++, можно же это упражнение использовать для освоения современного C++, не пользоваться небезопасными практиками в стиле C. Вам виднее, но, всё-таки, это же сайт, на котором ваш код могут прочитать начинающие C++ программисты, такой стиль может их озадачить.

Я взглянул на код автора заметки — де-факто выражение разбирается рекурсивным спуском (технически рекурсии, впрочем, пока нет — она появится, когда автор реализует скобки — когда VMCompiler::parseFactor начнёт вызывать VMCompiler::parseExpression для обработки выражения в скобках), простая грамматика выражений понятна из кода — конечно, выписать её полезно. Выделение фазы синтаксического анализа нет, это — однопроходный компилятор.


Меня больше расстраивает, что автор пишет на смеси некоторых элементов современного C++ (constexpr, enum class) и низкоуровневого C (везде указатели, не ссылки, рискованная адресная арифметика, невнятные отношения владения без смартпойнтеров — сырой указатель на вектор токенов tokens, пары указатель / длина) — не понятна цель упражнения "вспомнить C/C++", зачем это вспоминать, можно же писать более чисто и безопасно на современном C++. Жалко.

Согласен с аргументом в пользу C++ бэкенда (про использование конкретных удобств, перегрузки операторов в вашем случае). Меня беспокоит нетривиальная модель жизненного цикла объектов в C++ — в случае, если C++ бэкенд на неё закладывается, она может протечь в семантику разрабатываемого языка, привнося риск искусственного усложнения. Если в генерируемый C++ коде не опирается на автоматический вызов деструкторов, жизнь проще… Однако, если, например, поддаться соблазну использовать хотя бы unique_ptr, вещи усложнятся.


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

Здравствуйте, меня интересует тема и, возможно, мои (довольно поверхностные) наблюдения могут оказаться вам полезными.


Первое. Транспиляция в C (не в C++) может быть более гибким решением, когда вы будете добавлять понятие объекта. Семантика управления жизни объектов С++ — довольно специфическая, привязка к ней, с одной стороны, ограничит выбор возможностей, а, с другой стороны, повлияет на уровень сложности не в лучшую сторону. В качестве примера языка, старающегося избегать эти проблемы, приведу Nim. Его флагманский бэкенд — C (C++ бэкенд есть, но он альтернативен и, вероятно, не поддерживает недавно добавленные возможности Nim). В C++ деструктурирование объекта, даже уже перемещённого куда-либо, обязательно — поэтому перемещающие конструкторы, операторы присваивания должны заботиться об "опустошении" перемещённого объекта, чтобы при выполнении деструктора ничего не происходило. Такое (необязательное, если проектировать язык с ноля) усложнение специфично для C++, поскольку move-семантики не было в начальной версии языка, а когда она была введена позже, её нужно было "гладко" примирить с предшествовавшими правилами (диктующими обязательность вызова деструктора). В Nim, насколько я понимаю, эта лишняя сложность преодолевается: деструктор — лишь один из способов уничтожить объект, одна из потенциально нескольких "поглощающих" объект функций (хотя и наиболее стандартная и частоупотребляемая). Не знаю, как авторы Nim примеряют это c правилами C++ в C++-бэкенде языка (если оный не заброшен). Также, транспиляция в C кардинально упрощает проблемы FFI, бинарной совместимости раздельно скомпилированных библиотек. У C++ с этим — большие проблемы. Любопытное стороннее ответвление темы про объекты — в языке R более одной "системы объектов", запрограммированной поверх ядра языка в виде библиотеке.


Второе. В ваших примерах вы объединяете последовательное выполнение ("императивное") с бэктрекингом в духе Пролога ("декларативное" — под которым, на самом деле, в Прологе подразумевается более сложное императивное исполнение — с бэктрекингом; в частности, в Прологе порядок выражений, перечисленных в правой части через запятую, играет важную роль в плане производительности и вообще завершаемости исполнения "декларативной" программы). Обратите внимание на концепцию алгебраических эффектов (хорошо развитый пример — Koka, который, кстати, в новой версии тоже транспилируется в C), объединяющую под одим зонтом не только эти два аспекта, но и эффекты другого рода — исключения, завершаемость, асинхронность, недетерминизм, сторонние эффекты (state), асинхронное исполнение… (язык позволяет программировать новые эффекты кроме определённых в базовой библиотеке). У Koka — солидный математический фундамент: система алгебраических эффектов обладает свойствами, похожими на комбинирование монад в Haskell, при более компактных "церемониях", ложащихся на плечи программиста, использующего язык. Кстати, ещё один интересный аспект Koka — минималистический синтаксис, например, синтаксис while { тут условие } { тут действие } — это не встроенная конструкция языка с ключевым словом while, а вызов функции while, принимающий два параметра — анонимные функции. В Nim есть похожие синтаксические идеи, но Koka — более изящен в этом плане.


Третье — система гигиенических макросов может обеспечить минимальность ядра и богатый, знакомый "программистам на языке ..." синтаксис запрограммированный в базовой библиотеке поверх макросов. На ум приходит Racket (потомок Scheme, язык с богатыми средствами построения DSL) — к сожалению, для использования Racket нужно погрузиться в его лиспоподобный мир. С другой стороны, система гигиенических макросов регулярно появляется в современных языках (примеры: Nim, Rust, Julia) — это хороший способ сохранять ядро языка компактным, а богатство (выразительность) синтаксиса выносить в библиотеки.

"В реальном алгоритме приведет к n операций умножения" — это если в лоб, можно же быстрее (log n). Материалы на Хабре по теме:
N-е число Фибоначчи за O(log N)
(вместо формулы Бине используется быстрое вычисление по рекуррентной формуле посредством возведения матрицы в степень — сложность та же)
Используем быстрое возведение матриц в степень для написания очень быстрого интерпретатора простого языка программирования
(интересное развитие темы с обобщением на широкий класс рекуррентных последовательностей).
Вижу комментарий от eandr_67 ниже, в котором тоже упоминается сложность O(log(n)) — но без ссылок на существующие заметки, так что публикую ссылки здесь, мало ли, кому будет интересно.

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


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


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

Недавно вышел именно учебник, "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.

Could you please correct this fragment (following up with correspondent corrections below it)?


In our use case, however, we will be just fine with the maximum value for an int64. Any of these will do:

minLn := 1 << 63 - 1

minLn := math.MaxInt64

The first variant is incorrect — and you picked the incorrect one out of two! Worse, you formatted this bad expression later on as 1<<63 - 1 — no spaces around << to kind of stress the fact that as you think this operation has the higher precedence over -.


No it does not. You need parentheses around 1 << 63. Go has C-style precedence of operators and - is one step higher in the precedence order than <<, so your expression yields the same result as 1 << 62 which is not what you meant. Check this table, for example: https://www.tutorialspoint.com/go/go_operators_precedence.htm.


Please correct!

Я первым делом заглянул в Википедию, там есть небольшой список литературы.
ru.wikipedia.org/wiki/%D0%92%D0%BD%D0%B5%D1%88%D0%BD%D1%8F%D1%8F_%D0%B0%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0
en.wikipedia.org/wiki/Exterior_algebra
Английская статья — значительно более обстоятельная.

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

Information

Rating
Does not participate
Registered
Activity