Pull to refresh

Comments 59

Поясните, почему существует проблема:
«Во-первых, это бессмысленные имена переменных (потому что это вспомогательные переменные из исходной научной статьи, не несущие смысловой нагрузки).»

Разве нельзя переменные обозвать осмысленно и в комментариях подписать, как они назывались в статье?
Вы видно давно не открывали учебник алгебры :)
Вроде бы и понятно, что речь о точках и коэффициенте k но вот что за ними там стоит и что это за точки…
А разве в вашем примере имена переменных бессмыслены?

Вот если вы уравнение прямой запишите в виде (a-b)/(c-b) = (d-e)/(f-e), то понять, что за формула перед вами может быть тяжело. Запись же (y-y1)/(y2-y1) = (x-x1)/(x2-x1) сразу же скажет вам, что перед вами за уравнение.
На самом деле (y-y1)/(y2-y1) = (x-x1)/(x2-x1) не очевиднее чем (a-b)/(c-b) = (d-e)/(f-e) если вы только не понимаете полностью о чём речь. А вдруг это никакие не прямые, а хитрые преобразования для выявления групповых свойств объектов a,b,c,d,e

Вы только запутаете сами себя, и усложните отладку, заменяя те переменные которые были в статье своими выдумками.

На самом деле есть некоторые нормы (во многом неписанные), относительно которых в математических статьях выбирают имена своим переменным, например в работе по теории устойчивости врядли обзовут переменную e, а в Алгебре наоборот, радостно буковй е обозначат базисные векторы котого-нибудь подпространства R, которое бы в матанализе приняли за Действительные числа.
Еще есть извращенный способ- макросы, типа так
#define a accelerate
Смысл? Если вы хотите использовать в коде a — то accelerate вообще не нужен. Если же в коде будет accelerate, то вы замучитесь проверять правильность переписывания формулы («на бумажке» будет а, в коде accelerate; а таких переменных с десяток; и храни в голове все ассоциации) — уверен, что наошибаетесь еще больше.
Вот например, метод прогонки для решения трехдиагональной матрицы. Коэффициенты в принципе никак не назовешь иначе, потому что они не несут собственного смысла. В то время как в формуле можно допустить парочку ошибок.
Очень часто коэффициенты вводятся как части одной большой формулы, выражаются друг через друга, из них получают другие коэффициенты с целью оптимизации итд.
Тут согласен. Спасибо за пояснения.
Для меня скорее непонятна сама постановка вопроса — как имя может быть бессмысленным, если это — обозначение величины из статьи? Если есть величина, скажем, t — то это самое что ни на есть понятное и осмысленное название для переменной времени, и никаких вопросов с ее пониманием быть не может (у человека, который понимает какие формулы тут реализованы, конечно — но я надеюсь, что никто не надеется написать рабочий алгоритм расчета, не понимая, что же он считает).
а если есть величина b, которая равна S*t-int_0^1 g(x)dx/(2*pi), то какой у нее смысл?
А какой смысл у любой другой переменной? Например, у переменной categoryIsEnabled?
Смысл переменной появляется только в контексте чего-либо. В контексте вычисления величины, скажем, такого вида:
V = V0 + S*t-int_0^1 g(x)dx/(2*pi)
у указанной величины b смысл будет — изменение величины V относительно начального состояния.

Я хочу сказать, что если у нас есть ряд формул, в которых фигурирует N символов — то каждый из этих символов (или его ближайшая корректная для компилятора транслитерация) является наиболее удобным и самоочевидным названием для переменной, которая содержит величину, соответствующую этому символу.
название у переменной есть, но оно ничего не означает.
переменные categoryIsEnabled и categoryIsDisabled осмысленные и если вы их перепутаете, то из кода это будет видно
переменные S и Q — бессмысленные и если вы вместо S*t-int_0^1 g(x)dx/(2*pi) напишете Q*t-int_0^1 g(x)dx/(2*pi), то не сверяя очень внимательно с оригиналом (в котором, кстати, может быть опечатка), вы ошибку не заметите
У нас явно разный стиль мышления.
Для меня за каждой буквой в формуле, которую я понимаю, стоит весьма насыщенный образ, и S от Q для меня отличается как минимум не меньше (а скорее больше), чем categoryIsEnabled от categoryIsDisabled. В частности, если речь идет о каком-то движении жидкости, то S это скорее всего площадь, а Q — вероятнее всего расход.
Кстати, если в оригинале будет опечатка, но при этом я понимаю суть происходящего, то я эту опечатку и обнаружу при переписывании формулы в код.
Видимо разный.
В формулах бывают переменные, которые физического смысла не несут, а используются для сокращения записи
Обычно люди все же пытаются сгруппировать подобные переменные так, чтобы в них была определенная смысловая нагрузка. Например, член, связанный с давлением, член, связанный с гравитацией, и т.п.
В крайнем случае — член, который используется многократно в разных частях алгоритма, и поэтому заслуживает отдельного внимания и вычисляется отдельно.
А других, не считая промежуточных символов, которые объявляются за две-три строки до использования, я пожалуй никогда и не видел, несмотря на то, что уже много лет пишу в основном научный код…
выше ссылку давали на метод прогонки
Но я так и не понял, что там непонятного. Есть метод, в котором участвуют три диагонали — обозначаемые соответственно тремя буквами, и вычисляются вспомогательные величины и коэффициенты, обозначаемые буквами F, альфа и бета. Роль каждого из них в общих чертах понятна даже при беглом прочтении, а уж если вникнуть — станет абсолютно прозрачной. Спутать же 20% понятных символов при записи формулы (т.е. один из пяти в нее входящих) — и умудриться не заметить это при первой же проверке — надо постараться, я так не умею.

Т.е. никакие другие имена переменных не будут более интуитивно понятными, и такие как в алгоритме — интуитивны в достаточной степени, чтобы с ними можно было комфортно работать.
Как это опровергает тот факт, что имена переменных альфа и бета бессмысленные?
Они не бессмысленны!
Мы представляем Xi как сумму альфа на Xi+1 плюс бета — это коэффициенты перехода от Xi к Xi+1. Или для вас это тождественно слову «бессмысленно»?
Имена бесмысленные, а не переменные. Вы сразу понимаете что такое альфа, а что такое бета, когда смотрите на название переменной, даже не видя формул? Если да, то это талант
А вы сразу понимаете, что означает categoryIsEnabled (кроме того, что это что-то про категорию — т.к. я тоже могу сказать, что alpha[i] — это про коэффициент альфа, который индексируется i), не зная бизнес-логики? Если да — то это талант! :)
Смотрим статью.
В примере кода про категории, даже если я не знаю бизнес-логики — ошибка очевидна.
В коде для прогонки, если будет написано x[i]=alpha[i+1]+x[i+1]*beta[i+1], я ошибку не увижу, если не знаю точно что он делает, и то не факт
Ни разу не очевидна там ошибка:
categoryIsVisible = categoryIsEnabled || productsCount > 0;
Может, категория должна быть видна если мы отдельно отметили ее как видимую, посмотрев список обязательных категорий, или если в ней уже есть хоть один продукт.

Ну и для сравнения вот такой вот код:
x[i]=x[i+1]*alpha[i+1]+x[i+1]*beta[i+1]
— с большой вероятностью содержит ошибку, т.к. у нас одна и та же величина умножается на разные коэффициенты, и складывается. Хотя возможно, это такой специфический процесс, где удобно явно разделить вклад в результирующее значение от двух составляющих.
Ошибка ошибке рознь. То что часть ошибок незаметны (или заметны) в обоих случаях не значит, что проблемы нет.

Я не понимаю вашу позицию. Вы не согласны что говорящие имена переменных уменьшают вероятность ошибки? Или вы считаете, что alpha содержит столько же смысла сколько categoryIsEnabled?
Моя позиция в том, что человек, разбирающийся в алгоритме, который собирается запрограммировать, не сталкивается с проблемой «неговорящих имен», для него действительнот alpha содержит столько же смысла, сколько categoryIsEnabled. И никакая другая система имен, отличная от «х — альфа», не снизит вероятность ошибки, а скорее наоборот, повысит ее.
А если этот человек смотрит на код через 2 месяца после его написания?
Если человек все еще помнит алгоритм — то ничего не изменится. Если уже не помнит — то моя позиция к этому человеку в этом состоянии не относится, но кое-что я утверждать все равно могу: никакие «говорящие имена» длиной в пару слов не помогут человеку понять, где ошибка в более-менее сложном математическом алгоритме, сути которого он не понимает.
Так ведь о том и речь. В сложном математическом алгоритме имена переменных не позволяют найти ошибку. В бизнес-коде — позволяют (в разумных пределах конечно).
Но это следствие только крайне простой логики, обычно используемой в бизнес-приложениях. Если же там логика существенно нетривиальна — то проблемы будут точно такими же, имена не помогут.
Ведь если мы зададимся некоторой конкретной задачей из области математики, например 2мерной моделью течения жидкости, то однобуквенные имена переменных вполне позволят там искать простые ошибки человеку, который более-менее разбирается в этом вопросе.
Рад, что вы, наконец, согласились что проблема есть.
Это проблема не невозможности дать понятные имена, а сложности кода в целом. Если бы в бизнес-логике необходимо было построить итеративный процесс со сложным рекуррентным вычислением переменных — то подобрать им такие имена, чтобы код был сколько-нибудь ощутимо самоочевиднее, чем код из однобуквенных переменных — в общем случае не выйдет.
> Проверить перевод величин

не уверен на счёт данного случая, но если говорить о единицах измерения, то тут нам может помочь компилятор!
например, F# следит за единицами измерения и адекватно воспринимает из преобразования, проверяя что нет ошибок.
Да, размерность проверять — это первейшее дело в физ. расчетах
Да, есть такая возможность у F#, но здесь она не поможет. Если интересно, то можете пройти по ссылке [4] из статьи и просмотреть пункты 3.2, 3.3. Там дело как раз в специальных ограничениях на перевод величин.
Попробую поделиться методами, которые приходилось использовать.
Тестирование сеточных методов и мат моделей:
1. Удвоение сетки
2. Смена степени или способа интерполяции (если применимо)
3. Поворот системы координат
4. Проверка закона сохранения энергии и изименения общего возмущения системы для нестационарных задач
5 Получение ошибок на заведомо недостоверных данных
6 Добавление малых весов на главную диагональ (это возле несжимаемости как раз)
7. Экспериментальная проверка :)
8. Сравнение с аналитическим решением по скоростям, расходам и тп
9. Обезразмеривание постановки
10 Использование Ansys и подобных пакетов :)
11 Проверка результата на соответствие здравому смыслу :)
12 Вычитание решений (см невязка энергии или мощности)
13 Итерационное уточнение после прямых методов
14 Варьирование размера вещественных чисел (двойная, одинарная точность...)
Отличный список, спасибо! Многие способы использовал, но собрать воедино не доходили руки :)
По собственному опыту могу сказать только одно: нужно использовать не юнит-тестирование, а тестирование на простых граничных случаях, каждый из которых подчеркивает роль той или иной составляющей расчета, и сравнивать результаты с теми, которые должны быть. Из всех методов, которые мне приходилось применять, этот — самый действенный, вплоть до того, что иногда я таким образом определяю, какой должен быть правильный знак в том или ином месте: прогнать тест можно за минуту, а считать руками — минут 5, и легко можно ошибиться в конце дня (я занимаюсь в основном новыми исследованиями, поэтому у меня в принципе не может быть статьи, с которой можно свериться, но этот метод — работает).
а не задавались вопросом — что будет, если «тестирование на простых граничных случаях» засунуть в юнит-тестирование?
Это немножечко нетривиальная задача. По крайней мере у меня граничный случай — это определенные параметры и конфигурация системы управления и объекта управления. Как это превращается в числа, поступающие на вход отдельным функциям, и что должно быть у них на выходе — у меня нет ни малейшего представления, на подобный анализ нужно в разы больше времени, чем собственно на исследования по сути.
а никто не говорил, что будет просто ;) тесты просто помогают решить проблему 1 раз…
что должно быть у них на выходе — у меня нет ни малейшего представления

тут мне видится только 2 рабочих варианта:
1. вы осиливаете предметную область и получаете представление, сами готовите данные.
2. вам дают тестовые данные те, кто в теме, они же — основные тестеры.
технически, конечно, проще вариант 2… но бывают организационные нюансы ;)
короче, это отмазки перед самим собой ;) окружающих вы не убедили ;)
>1. вы осиливаете предметную область и получаете представление, сами готовите данные.
>2. вам дают тестовые данные те, кто в теме, они же — основные тестеры.

Я безусловно «осилил» предметную область :) По крайней мере в нашей стране я не знаю человека, который мог бы мне ответить на мои вопросы, не потратив на это примерно такое же время, какое нужно мне, чтобы найти ответы. Однако что делать, если в принципе неизвестно, какой промежуточный результат — «правильный»? Заняться полноценным теоретическим исследованием этого вопроса? А кому это нужно, кто будет финансировать эти исследования (не говоря уже о том, что это — бесконечно скучно), ведь правильный результат работы комплекса в граничном случае — априори известен, и его легко сравнить с тем, что получилось практически?
я делал так — брал исходные данные, к которым известен правильный результат, фиксировал тестами основные промежуточные значения. и так несколько раз ;)
в итоге при уточнении алгоритма есть контрольные точки.
если работа исследовательская и нет ни 1-й достоверной пары данные-результат то тут, ихмо, только эксперимент, что таки да — обычно дорого ;) но без эксперимента голые расчеты это как:
— а есть ли жизнь на Марсе?
… после продолжительного рассказа…
— а науке не известно, есть ли жизнь на марсе ;)
Я бы еще упомянул ошибки связанные с погрешностью численных методов и трудности связанные с невозможностью (на практике) проверить результаты вручную
Да, это очень важное ошибкоёмкое место. Ндавно вот писали небольшую математическую программу, вроде-бы выполняющую не сложные операции, но на деле, кроме как написать ещё одну программу которая будет проверрять эту — способа проверить результаты то и нет))
Интересно, что это за задача, в которой подстановка граничных случаев не работает? :)
Она конечно Работает, но эта ирония такая) Суть иронии в том что программа небольшая, и по этому проще написать ещё одну программу чем разработать и посчитать вручную граничные случаи)
а… ну так это нормальная ситуация :) Просто обычно в таких случаях имеет смысл проверочную писать на каком-нибудь матлабе, где наверняка найдутся готовые функции, сильно упрощающие процесс написания.
Я кстати так и хотел) Но потом плюнули, заточили карандаши — сами посчитали))) Вспоминать синтаксис матлаба было ещё более лениво)))
Я кстати так и хотел) Но потом плюнули, заточили карандаши — сами посчитали))) Вспоминать синтаксис матлаба было ещё более лениво)))
ну, как говорится, при всем уважении к тем, кто пытается участвовать в научной/около научной работе, не могу согласится с выводами ;)
как уже писал в комментах на 1-ю статью — не до конца используете возможности юнит тестов… ваша проблема решается автоматической/полуавтоматической подготовкой данных для юнит тестов (возможно, нужно сделать мини редактор для пользователей, владеющих предметной областью, или научить их использовать Excel/Matlab/...). если добиться предоставления тестовых данных для принципиально различных ситуаций, желательно и с «граничными» условиями (если есть), то при написании реализации будет меньше шансов пропустить мелочи…
короче, автор не сделал выводов из комментов, к упомянутой в начале статье ;)

P.S. на ум приходит только «мыши плакали, кололись, но продолжали...» ;)
Ну вот могу привести вполне конкретный пример, авось вы подскажете, как разобраться :)
Есть динамический объект, который получает на вход управление, на выходе дает свое состояние.
Есть нейронная сеть, которая учится повторять его поведение — т.е. вести себя так, чтобы если дать ей на вход прошлое состояние объекта и управление, она вернула новое состояние объекта. Сеть здорово обучается, отклонение ее оценки от реальных выходов объекта — несколько процентов.
Далее, эта сеть анализируется как инверсная модель объекта (грубо говоря, даем на вход два управления, различающиеся на малую величину, сравниваем результаты — и получаем производную от выхода по управлению в окрестности данной точки).
И эта производная используется для того, чтобы учить другую нейронную сеть управлять объектом так, чтобы его выход принимал определенное значение (применяем то, что эта сеть посоветовала, смотрим на производную, корректируем ее поведение так, чтобы выход стал ближе к целевому значению).
В результате имеем довольно плохое управление.
Примечание: та же сеть отлично управляет объектом при другом методе обучения.

Теперь вопрос — как убедиться, что это плохой метод, а не ошибки в вычислениях на каком-либо шаге? Вопрос усложняется тем, что отличный метод придуман мной, описанный — авторитетными товарищами, т.е. довольно маловероятно (хотя я, конечно же, надеюсь на это :))), что у меня все правильно, и действительно такой известный метод так слабо работает.
как проверить — очень просто :) — практическим экспериментом ;)
а если серьезно, то вопрос корректности того, насчитали стоит очень остро… не раз и не два бывали случаи, когда приходит аспирант/молодой научный сотрудник/просто фанат от математики на конференцию по конкретной теме(мне про акустику рассказывали) и заявляет — я решил ВСЕ ваши проблемы — я ВСЕ посчитал в matlab/mathcad/отдельная софтина… пока он размахивает руками про алгоритмы его особо не беспокоят, а когда пришло время задавать вопросы, вылазят «зубры» в этой теме, часто далекие от тонкостей компьютерных дел и просят просчитать несколько ситуаций по их данным… в конце требуют обычно график или другую визуализацию(просто по цифрам таки дольше обычно), а по графикам/картинкам/… часто все видно «на глаз» и вот тут оказывается по конечной картинке, что расчеты та того — мимо кассы ;)
так, например, у нас на физтехе препод проверял правильность курсовых на тему «расчет фильтра.....» и по прочей электро технике. он говорил — считайте на чем хотите. результат проверял по графику — и все — если не то, что он ожидал — в сад без вопросов — расчеты совать было бессмысленно ;) правда, прокачав скилл по этому делу, некоторым стал понятен принцип — какой должен быть график на какое задание ;) после этого мой товарищ неплохо подработал на курсовых — смотрим формулу — рисуем график, подкладываем практически любые расчеты — лодырь сдает задание ;) препод, похоже, так и не узнал, как 5-7 лодырей за неделю сдали курсовую, которую делать около месяца в нормальном темпе ;)
итого — серебряной пули нет ;) проверка корректности результатов — отдельная тема. есть такой раздел в науке как «экспериментальная физика» — так вот их методы, обычно, наименее спорные ;)
вообще ВСЕ мат. моделирование упирается в то что, в КАЖДОЙ модели есть неточности вопрос только в том — допустимы ли они для нас… поэтому разработка научного софта получается долгой, дорогой, и все равно используемая модель может иметь недостатки…
моя софтина прошла проверку натурными измерениями для тех случаев, которые стояли в ТЗ(для более сложных случаев, естественно, был разбег, но их и мерять было не всегда понятно как) — только это дало возможность говорить что проект готов для реальной эксплуатации…
короче за тысячи лет ничего не изменилось ;) — 1 эксперимент может опровергнуть 1000-чи теорий, но 1000-чи успешных экспериментов не гарантируют 100%-й правильности даже 1-й теории… так что в науке иногда канает способ, описанный для курсовых — хрен поймеш что не так — выглядит то все классно… и некоторые этим пользовались,/пользуются/будут пользоватся ;)

во, блин сколько накатал — больной вопрос задели ;) надеюсь, на полезные мысли натолкнул…
Так тут как раз с экспериментом проблема — один метод работает хорошо, один плохо, ну и стандартный тест в виде пид-контроллера — средне. Там где хорошо — вопросов нет: получить отличный результат из-за ошибки практически невозможно. А вот там где плохо — надо понять, это результат ошибки, или нет…
Т.е. публиковать статью «зацените, как круто получается» я уже могу смело, а вот статью «смотрите, насколько это круче того, что было» — как-то боязно :)
а вот статью «смотрите, насколько это круче того, что было» — как-то боязно :)

и это правильно ;)
был когда-то в нашем универе 1 доцент, который интересовался теорией относительности и любил он чего-то посчитать ;) как-то насчитал он немерянное открытие, которое могло потеснить упомянутую теорию и сулило кучу всяких плюшек… не знаю, показывал он это все кому-то или нет, но человек он был деятельный и на основе «открытия» начал вести дальнейшие работы, проталкивая свои достижения, брошюру выпустил со своими достижения — мол как он лихо «обошел» Эйнштейна и прочих физиков… даже в газете местной написали «мол местного гения поддержать надо — а то не дают бюрократы талантам дороги»… и так было все красиво расписано, что я не поленился и откопал где-то эту брошюру на 20 или более листов с кучей формул… после 2-х страниц введения (в стиле я дартаньян, а у остальных не вышло), на 3-й было 2-3 базовых формулы, на которых строились все дальнейший построения… так вот в 1-ной из них была ошибка уровня «при переносе слагаемого слева на право знак не поменян» ;)))) я 2дня втыкал на ту формулу и не мог понять — это я такой умный или он протупил? ;) показал корешу, тот тоже подумал как и я ;) надо ли говорить что дальше никто не читал? ;) а человек нобелевскую премию хотел и думал, что вокруг заговор ;)
так что «торопись не спеша» :)
Не, ну это бывает конечно, но у меня есть золотое правило: если я сделал гениальное «открытие» — то сегодня я делаю вид, что ничего не случилось, а завтра — перепроверяю. Работало десятки раз. Ну и еще пару раз работало второе правило: «перепроверил сам — покажи другу, который будет смеяться не слишком громко» :)
Disclaimer: к сожалению, после написания той статьи у меня не было возможности применить советы из комментов к прошлой статье, хотя они были полезными (кстати, спасибо!). Возможно, многие трудности из прошлой статьи частично бы решились.

Но почти все сложности из этой статьи остались бы. Дебаг параллелизма--сложнее и с юнит-тестами (хоть его и реже нужно будет применять); неочевидность ошибок остается (даже после юнит-тестов вы знаете, что в таком-то методе из 20 строк ошибка, вы далеко не сразу ее найдете); влияние сеттинга на результат вообще не зависит от юнит-тестов; при идентификации ошибок часто бывает так, что отклонение в работе--это не ошибка, и все тесты пройдут, и все равно придется мучаться с входными данными, заменой алгоритма и средствами из вот этогокоммента. Может быть, нелокальность ошибок будет легче анализировать.
про параллелизм — боролся так — программу сделал рабочей и в 1-поточном варианте и в распределенном (переключал дефайнами). соответственно проверил обычную версию, и когда в распределенной результат такой же — спим спокойно :)
А вот и вспомнился реальный пример насчет юнит-тестов. Все в том же потоке по трубе известно аналитическое решение. Положим, я пишу тест (системный, табличный), который сравнивает моделирование с аналитическим решением. Оказывается, что порог принятия решения по ошибке надо установить в 1е-6 из-за особенностей алгоритма (то есть 1е-6--это максимально допустимая норма вектора ошибки). Но потом, когда после рефакторинга я перепутал в одном методе break с continue, через 100000 итераций моделирование стало асимметричным по сравнению с первоначальным на 1е-10. И этот тест бы ничего не обнаружил.

В общем, «мыши плакали, кололись, но продолжали жрать кактус, потому что кактус так и остается кактусом даже после юнит-тестов».
мне только кажется что вы не тестируете алгоритм по частям или так и есть? ;)
Sign up to leave a comment.

Articles