Pull to refresh

Первобытное мышление или история магической единицы

Level of difficultyEasy
Reading time4 min
Views6K

В своей книге "Первобытное мышление" Люсьен Леви-Брюль рассказывает, как люди из первобытных обществ, даже прожившие долгое время в цивилизованном обществе, продолжают верить в колдунов и магию. Его теория состояла в том, что первобытные народы склонны к так называемому дологическому мышлению, тогда как представители современной цивилизации опираются в своих суждениях на логику. Леви-Брюль, однако, ошибался. Ниже я покажу, как люди из цивилизованного общества, получившие образование в ведущих ВУЗах страны, начинают верить в магию даже в той области, в которой они являются профессионалами. Имена, названия и высказывания изменены так, чтобы никто не нашёл себя и не обиделся.

Работал я тогда в компании среднего размера. Несмотря на средний размер, это была компания, которая продавала свой продукт в передовые страны запада, а это всё-таки показатель высокого качества. И работали там не простые программисты, а выпускники мехмата МГУ, МФТИ и прочих уважаемых ВУЗов. Но был в этой компании момент, который меня конкретно выбешивал: мне постоянно повторяли, что без особой необходимости не надо ничего менять. Как-то, помнится, нашёл я в коде строку

x = (a + b * c + d) * (g - sin(alpha) * cos(beta) ) * (cos(d5) + d8 + d11) / (k - t * p) / (d7 + d9 + d15);
y = (a + b * c + d) * (g - sin(alpha) * cos(beta) ) * (cos(d5) + d8 + d11) / (k - t * p) / (d7 + d9 + d15);
z = (a + b * c + d) * (g - sin(alpha) * cos(beta) ) * (cos(d5) + d8 + d11) / (k - t * p) / (d7 + d9 + d15);

Ну я взял и поменял на

x = y = z = (a + b * c + d) * (g - sin(alpha) * cos(beta) ) * (cos(d5) + d8 + d11) / (k - t * p) / (d7 + d9 + d15);

Не ускорения ради, а просто чтобы не мозолило глаз. Как на меня тогда напал наш группенфюрер...

Сейчас все модели сломаются! Потом скажут, что мы всё сломали! Я такие изменения не пропущу!

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

if (fabs (mult - 1.) > std::numeric_limits::epsilon ())  // this is needed because x * 1. != x if x << 1
{
    factor *= mult;
}

Как мы видим, стоит проверка, что если отличие множителя от единицы меньше численной точности представления (примерно 16 знаков для double), то умножение не производится. С точки зрения любого разумного человека эта проверка является совершенно бессмысленной, хоть и довольно безвредной (если конечно не считать вредом то, что людей заставляют верить в магию умножения на единицу). Однако автор кода оставил для нас комментарий, почему эта проверка важна: мол если множитель равен 1, то лучше не умножать, потому что это может изменить умножаемое число, если это число мало. Писал, очевидно, человек, который не знает, что в представлении с плавающей запятой числа хранятся так, что их относительная точность не зависит от того, равно число 1.e+100 или 1.e-100.

Мне стало интересно, как могло родиться такое, и я начал читать соответствующий "тикет". Не знаю, смогу ли я передать невероятное напряжение, захватившее меня, но я чувствовал себя детективом, расследующим убийство в романе Агаты Кристи. Детективом, расследующим убийство разума.

Среди тестовых моделей была одна, при запуске которой программа падала. Стали выяснять почему и оказалось, что движок требовал памяти больше, чем имелось на машине. Как часто бывает в таких ситуациях, когда умные люди, не имея дельных предложений, молчат, находится ограниченный, который предлагает какую-то херню. И такой человек немедленно нашёлся. Назовём его Коля. Коля "исправил" проблему: при превышении размера имеющейся памяти программа стала корректно завершаться, а не просто падать. Кроме этого весомого вклада в решение Коля обратил внимание, что падающая модель невероятно сложна: содержит аж на три элемента больше, чем другие модели, движок не справляется и давайте использовать магическое слово "СЛОЖНАЯЗАДАЧА" для решения таких моделей. Как также обычно бывает, вместо того, чтобы сказать ограниченному, что он ограниченный, большинство соглашается с его предложениями, а умные люди продолжают молчать. Но оказалось, что модель всё равно продолжала падать, правда теперь уже на кластере.

Тут, как в книге Леви-Брюля, впору бы уже признать, что виноват колдун, который наслал порчу на кластер, но главный эксперт по кластерам Алик понял, что причина падения в том, что кластер пытался выделить слишком много памяти на NUMA-узле (хм... мне кажется, мы уже где-то это видели), и пообещал придумать, как защитить кластер от этого хитрого колдунства.

В этот момент вмешался технический директор и начал спрашивать, что мол никого не удивляет, с какого перепуга узлу потребовалось 70 гигов памяти, но ему быстро объяснили, что причина в страшной модели (в сочетании со страшным колдунством конечно же), и он перестал мешать людям бороться с колдунством: в модели что-то подкручивали, что-то меняли, но колдунское проклятие было слишком сильно и ничего не помогало. К концу года проблему так и не победили и просто перестали обращать на неё внимание. Однако через несколько месяцев (!) некто, назовём его Муся, сделал наброс на вентилятор, написав, что мол Вова своим множителем mult сломал модель. Это ключевой момент в истории, поэтому обратим внимание терпеливого читателя на то, что модель и без изменений Вовы не работала уже больше года. Просто после изменений Вовы она стала выплёвывать другие ошибки.

По-хорошему Вова мог бы призвать участников дискуссии к разуму и объяснить, что его изменения вообще не затрагивали тот кусок кода, где происходило падение, и что оно происходило и до его изменений. Но какой разум с этими людьми? И Вова нашёл наилучшее решение проблемы: поставил условие, что если множитель равен единице, то не надо домножать на этот множитель. И заодно вкатил туда псевдонаучное объяснение, что мол x * 1. != x. Однако это бессмысленное изменение сделало главное: проблемная модель снова стала глючить точь-в-точь, как глючила до этого.

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

Итого: проблема решена, модель работает, и все верят в то, что маленькие числа лучше не умножать на единицу. Занавес.

P.S. Вот из-за таких случаев я всё больше утверждаюсь во мнении, что образование в ведущем ВУЗе вообще не гарантирует, что человек умный: иногда я вижу перед собой обезьян, которые умеют решать дифуры.

P.P.S. Если вы, прочитав мой текст, хотите спросить "а что не так?", сразу отвечу. Не так тут то, что проблему, к которой человек не имел никакого отношения, свалили на него, вынудив вставлять бредовую проверку близости числа к единице. И после того, как проблему нашли, надо было заняться написанием кода, который бы проверял тестовые модели на валидность данных, а бредятину убрать. Но проверку не сделали, а код, заставляющий верить в магию, оставили.

Tags:
Hubs:
Total votes 38: ↑33 and ↓5+43
Comments68

Articles