Комментарии 45
Крыльчатка в ушла в производство в тираж, но «с тех пор в себе я сомневаюсь».
возможно используются и другие генераторы. Но по своей специфике работы скажу(тестирование авиационного ПО), что каждый используемый код генератор квалифицирован по do-178b/c.
Довелось тут запускать древний Electronics Workbench 5.12 под Windows 10. Результат моделирования выдавался абсолютно неадекватный. Собираю цепь — источник переменного напряжения, и простейший выпрямитель — диод плюс резистор. Напряжение на резисторе выходит переменное. Мда… Когда второй раз полез в опции анализа, оказалось, что все значения вида 1E-13 стали нулями. Где уж тут нормально считать! В принципе, оно было решаемо записью вида 0.0000001 в поле (на сколько нулей ширины поля хватало). Но была же ещё и куча таких записей в моделях элементов. Всё не переделать. В общем проблема решилась запуском в режиме совместимости то ли с семёркой, то ли с XP.
Проверка мат-пакетов статическим анализатором — это, конечно, хорошо. Но вы проверяете только C/C++ ядро. А сколько там кода, написанного на языке самого пакета (Scilab, MATLAB и т. п.)? Этот код вы проверить своим анализатором не сможете, потому что он динамический и интерпретируемый. И знаете, этот код ужасно написан, хотя бы с точки зрения качества кода и сколько там математических и логических ошибок можно только гадать.
Недавно ковырялся в официальном матлабовском коде
![](https://habrastorage.org/web/dcd/091/b8e/dcd091b8e52b41b489839c2132ce902a.png)
Там весь код тулбокса написан в таком стиле. Это очень сложно поддерживать.
Простите, я не очень понял. Какие претензии к тому, что подчеркнуто красным? Кроме жутких имён переменных, которые за матлабом тянутся с 80-х?
Дублирование кода. Вычисление матрицы QtWQ и вычисление выражение для u можно вынести из под условия if else. Условие тут нужно только для вычисления параметра p.
Там весь код так написан, очень сложно читать.
После того, как это сделано, оказывается, что оба вычисления для u имеют одинаковую форму:
u=((6*(1-p)*QtWQ+p*R)\diff(divdif)
и «else» вообще не нужна, а «then» просто меняет значение p; вычисление u может быть сделано общим кодом после завершения развилки.
Мне лично кажется, что после этих изменений код будет понятнее и сопровождабельнее.
Я, конечно, не могу залезть в голову разработчикам, но попробую предположить, почему сделано так как сделано.
Итак, как я подозреваю, речь об аппроксимации (сплайны?), а Qtw имеет специальный тип, описывающий разреженные матрицы (вызов spdiags). Причём, размерность n на n, где n, веорятно, это число точек кривой.
Если мы идём по ветке if, то приозведение Qtw*Qtw используется дважды — при вычислении p и при вычислении u. В этом случае разумнее избежать повторного очень дорогостоящего вычисления произведения и заранее его сохранить в QtWQ. Если же мы идём по ветке then, то нет необходимости повторного использования произведения, и мы экономим на создании в памяти ненужного (но большого!) QtWQ.
Таким образом, незначительно теряя в читаемости, мы выигрываем в производительности и без того ресурсоёмкой задачи.
Выигрыша нет, QtWQ безусловно и одинаково вычисляется в обеих ветках. Если написано Qtw*Qtw.', это оно же.
Или Вы предполагаете, что в else реально происходят «ленивые вычисления» и работа с QtWQ «размазывается» на остальном? Такое я про матлаб пока не слышал, хотя готов поверить, если подтвердят.
QtWQ нужно вычислять в любом случае, дублируя код мы ни в чём не выигрываем.
Заметьте ещё "однострочники" через точку с запятой. Ради чего тут экономия строк? Это трудно читаемо и усложняется отладка с помощью отладчика.
Я не говорил, что не производятся вычисления. Я говорил, что экономится время на создание новой переменной. Одно дело посчитать значения в ходе вычислений, другое дело создать новую переменную специального типа весьма большой размерности. Тем более, этот код, если я не ошибаюсь, многократно вызывается из цикла.
Я сделал небольшой бенчмарк по построению сплайнов для 10 тысяч точек. Разница совсем небольшая, порядка 0.1 мс на вызов, но предложенная netch80 версия достоверно оказывается медленнее. В доументации пишут, что первая версия этой функции была сделана в 1987. Я не знаю, когда именно был добавлен обсуждаемый участок кода, но у меня есть существенная уверенность, что на тот момент выигрыш в производительности был куда как более заметен.
Да, Matlab известен своим печальным оформлением кода (хотя, если Вы откроете другой код 80ых, то там, возможно, будет что-то похожее. Надо Fortran посмотреть). Но не нужно "негативный ореол" оформления автоматически переносить и на быстродействие/оптимизированность кода. Хотя да, проблемы, как и у всех крупных проектов, бывают.
Этот код в цикле не вызывается, матрицы там разреженные, поэтому то, о чём вы говорите — это какая-то уж совсем микрооптимизация получается. 0.1 мс против читаемости и поддерживаемости кода — это уже слишком, учитывая, что в матлабе вообще всё передаётся по значению (кроме handle based классов). Хотя о чём это я, ООП в матлабе в десятки раз медленее чем обычные функции. :)
В доументации пишут, что первая версия этой функции была сделана в 1987
Изначально этот код был написан на фортране Карлом де Буром для книги. Думаю, что первые версии матлабовского кода написаны им же.
Но не нужно "негативный ореол" оформления автоматически переносить и на быстродействие/оптимизированность кода
На матлабе тоже можно писать нормально, просто это никто не делает, потому что большинство пишут на матлабе write-only "наколенчатый код" лишь бы проверить работу модели или алгоритма.
первая версия этой функции была сделана в 1987
есть существенная уверенность, что на тот момент выигрыш в производительности был куда как более заметен.а Вы мне отвечаете
0.1 мс против читаемости и поддерживаемости кода — это уже слишком
В целом, я не могу понять Ваше тезис. Вы хотите сказать, что разработчики в 1987 году написали более сложный и хуже читаемый код без всяких оснований? Или что спустя 20-30 лет они должны были переписать существующий и работающий код, так как на новом железе выигрыш по времени стал слишком маленьким?
Последний раз этот код правился в 2010 (судя по документации). Я считаю, что код нужно писать так, чтобы он был понятен и легко поддерживаемым. Периодически надо делать рефакторинг. Это не тот случай когда надо упарываться по поводу создавать или не создавать переменную. Мы не живём в 1987 и на фортране уже почти никто не пишет (на самом деле пишут, но не в этом суть). Просто сидят вот такие математики и колбасят вот такой код. Я работал в двух компаниях где практиковалось такое программирование алгоритмов. И каждый раз подобный код просто выкидывался не использовался и писался заново, чтобы потом написать на его основе понятный C++-код для использования в production.
Объясняю свою мысль в контексте этой статьи: подобный код сложно читать и понимать, а значит в нём легко могут затаиться ошибки, которые трудно заметить. И бывает, что подобные ошибки, закрадывающиеся в формулы, даже тестами не отлавливаются.
Вообще, я понимаю, почему вы "защищаете" этот код. У вас в профиле написано, что вы работаете с Matlab. Для вас этот код выглядит совершенно нормально.
Я не перестаю писать о том, что код на Matlab ужасен в 99% случаев, потому что он написан математиками для "калькулятора", каким они считают компьютер, а не для людей.
Вот мой комментарий на эту тему:
https://habrahabr.ru/post/324052/#comment_10121034
Этот код вы проверить своим анализатором не сможете, потому что он динамический и интерпретируемый.
Вряд ли дело в этом :D Скорее у нас просто нет анализатора для этого языка.
Вряд ли дело в этом :D Скорее у нас просто нет анализатора для этого языка.
Именно так :) Ну и в том числе ловить ошибки статическим анализом в языках с динамической типизацией сложнее. Сделайте хороший статический анализатор для Python, которому не нужны аннотации типов, я вас расцелую куплю его. :)
1) нормальная работа
2) ошибка на определённой строке
3) подвисание программы
4) вроде нормальная работа, но конечный график — нули
Грешным делом подумал, что глюки 64-разрядной версии. Поставил 32-разрядную. Глюки те же.
А вон оно чё, Михалыч, оказывается…
По поводу этой ошибки, скорее всего вы нашли какую-то заброшенную часть кода, которая никогда не выполняется. Иначе бы эту багу уже давно заметили, уж слишком тривиально и ведет уж к слишком другому результату. Ну или этим пакетом просто никто не пользуется.
Так и живем.
Головная боль от использования математического софта