Pull to refresh
4
0.7
Send message

Меня больше радует открывающая. Сразу вспоминаю холивары 20-летней давности – писать её на отдельной строке или в той же строке, где if/while/хедер функции.

Ну конечно же программисты, разрабатывающие стэнфордский стандарт оформления кода и Ричард Столлман, создавший стандарт кодирования GNU, были глупее вас и не догадались добавить пустые строчки.

Первый совет (про пустые строки в начале и конце каждого уровня вложенности) я бы отнёс скорее к вредным советам или по крайней мере к попытке навязать свой экзотический Code Style (приемлемо, если вся команда его использует, но если нет – я бы крайне не рекомендовал внедрять). Не надо так.

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

"Вместо"? Никогда не слышал слова "ранбайк", а на bing количество результатов по запросу "runbike" меньше, чем по запросу "беговел". Т.е. тут ситуация обратная – есть уже прижившееся слово, которое никто не торопится переводить на английский.
Не удивлюсь даже, если это "runbike" калька с "беговел", а не наоборот.

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

Впрочем, я вообще не люблю такую рекурсию, я люблю вместо неё fold/zip/...

Я не в курсе, для чего может использоваться "автоматическая интроспекция" в данном случае (и вообще по возможности избегаю работы через рефлексию). Знаю только, что если убрать рекурсивный вызов внутрь try-catch или ещё чего, что должно обрабатывать результат вызова – это не хвостовая рекурсия :-)

Именно :-)

Очень наглядный пример – язык Objective C, с его "отправкой сообщения" вместо привычного "вызова метода". Наиболее заметное отличие – что можно отправить сообщение нулевому объекту, и он ничего не сделает. Порой это упрощает код (не надо делать 100500 проверок, что полученные нами объекты существует – к примеру, передали нам нулевое view, добываем из него нулевое же window и что-то с ним "делаем"), но порой изрядно затрудняет поиск ошибок (если такая логика не планировалась специально – лучше б упасть на первом же нулевом указателе), в результате в ObjC появились атрибуты __nullable и __nonnull. А в более поздних языках такие вещи вообще делаются явно, вызовом myObject?.myMethod(), что практически не загромождает код, но позволяет видеть, что ты делаешь.

"Выполнение в усечённом виде" порой заметно упрощает код (если у вас clean-up не в деструкторах или что там вам язык предоставляет для его автоматизации и вы не можете на любую ошибку делать return).

И теоретически убирание такого усечённого выполнения – довольно понятная задачка для оптимизирующего компилятора.

Положим, что касается хвостовой рекурсии – потеря N повторяющихся фрагментов в стектрейсе – не великая проблема.

Инлайн же сам по себе особо ситуацию не портит (если, конечно, отслеживание call stack не ведётся в лоб по stack frames).

Так что мешать оптимизации будет, но не в приведённых вами примерах :-)

Кажется, 70% текста из начала статьи можно было б скипнуть, если просто понять (и сказать), что классы в CSS – это не классы из ООП, а скорей классы (или множества) из математики.

Тогда и проблемы вроде конфликта small и big стали бы более понятными (и их можно было бы записать в виде ограничения small ∩ big = ∅), и его предложения было бы проще сформулировать и проанализировать.

  1. Это ж, наверное, какое-то типовое решение?

  2. А сразу в готовом виде сборок нету (ну или просто сборок вида N оптопар в одном корпусе)? Было б логично, чтобы гарантированно иметь одинаковые параметры транзисторов.

И какая гарантия, что в вызывающем коде будет написано "T foo{};", а не "T foo;"?

Звуковой ЦАП в идеале должен делать не так, а интерполировать значение между сэмплами, для чего ему нужно знать частоту оцифровки.

Если у вас в агрегате лежат только объекты – можете себе позволить. А если есть простые типы (int, указатели) – лучше б написать конструктор, чтобы потом не развлекаться в отладчике.

Окей, вероятно, я непонятно и коряво объясняю. Но суть простая: никакого выделения контуров (необходимого для использования второго правила Кирхгофа). Это критично.

Поясню на примере, почему критично: возьмите пять точек и от каждой к каждой проведите по линии (10 пересекающихся линий, эдакая пентаграмма). Ну и на линиях располагаем разные резисторы и источники напряжения. А теперь скажите, как вы выделите контуры для использования п.К.?

Не вижу проблемы.

А специально для вас могу вывести второе правило Кирхгофа из закона Ома для участка цепи. Просто чтобы вы убедились, что одно заменяет другое (в другую сторону тоже работает).

Да, и кстати: 99% любой софт, которым вы воспользуетесь для обсчёта схемы, тоже не будет использовать второй закон Кирхгофа. Просто в силу того, что для него надо решать лишнюю задачу – выбирать набор независимых контуров. Не слишком сложно, но зачем? А закон Ома для участка цепи идеально ложится на простейшее представление графа.

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

А "не обходились там контура" из вашего коммента https://habr.com/ru/articles/829058/comments/#comment_27047658 – довод? Вы радиоинженер ведь?

Про "получают результат , а не вычисляют его" напомню про такую чудесную вещь, как ПЛИС. Которые делают ровно то же самое, только не для вещественных чисел, а для двоичных. По сути, они получают результат комбинаторного выражения.
И вот тут как раз можно наблюдать несколько интересных моментов, которые объясняют переход к последовательному вычислению по программе.

1. В элементах ПЛИС всё ещё есть переходные процессы, поэтому правильный сигнал на выходе появляется не сразу. К счастью, есть способы оценить это время (достаточно удобно, софт считает и сразу выдаёт предельную частоту работы схемы) – и, естественно, с ростом сложности "схемы" оно растёт. В результате оказывается, что схема может производить вычисление не более N раз в секунду (подали на вход значение, через 1/N секунды забрали с выхода результат, можно подавать следующее). Если хотим обрабатывать больше N – надо как-то масштабироваться. Например, повторять всю схему несколько раз.
К счастью, нашлось более эффективное решение – конвейер. Делим схему на несколько (допустим, K) последовательных частей, добавляем сигнал тактирования, по которому каждая часть берёт сигналы со входа и начинает "считать" свой выход – и ура, мы всё ещё считаем результат за 1/N секунды или даже медленней, но уже можем за секунду получить порядка N*K результатов. Увеличили throughput, возможно, несколько ухудшив latency. Уже начинает напоминать программирование, такты какие-то появились...


2. Берём, к примеру, умножение чисел. Схема умножителя даже 8*8 бит оказывается весьма громоздкой, не говоря уж о 128*128. Разбиваем её на пачку умножений 8*8 и сложений и считаем последовательно – получаем огромную экономию логических элементов (транзисторов) за счёт снижения быстродействия.

3. Сложность. Разработать и отладить "программу" на verilog значительно сложнее, чем на C.

Т.е. начиная с некоторого уровня сложности "программирование" оказывается дешевле "непосредственного вычисления" как по ресурсам железа, так и по затратам труда разработчика. Но когда надо убирать Latency – альтернатив нет.

Думаю, что все эти рассуждения переносятся и на сравнение аналоговой схемотехники с цифровыми вычислениями. Тут пробегала статья, где описывались чипы для аналоговых вычислений – там, насколько я помню, как раз использовался конвейер.

Information

Rating
1,746-th
Registered
Activity