Нужен ли математикам статический анализ?
Есть такая профессия, в которой люди на 50% процентов занимаются программированием, но при этом сидят на порой весьма “несовременных” технологиях, пишут в основном на С++, и никаких особых бенефитов от IDE вообще не имеют. И при этом не жалуются. В этом посте – про то, кто эти люди, чем они заниматся и чем мы можем сделать их жизнь лучше.
Знакомьтесь – квонты
Квонт, он же quant (quantitative analyst – численный, так сказать, аналитик) — это человек, который занимается применением математики в финансах, часто – для создания торговых систем, т.е. программ, которые занимаются автоматизированной торговлей на бирже. Эти люди – чаще всего магистры или PhD в области физики (да-да) или математики (в частности, с дипломами вроде MFE – Masters in Financial Engineering), в некоторых случаях, с дипломом CQF (один из очень небольшого кол-ва “неакадемических” дипломов) или даже с MBA Finance или а ля.
Квонты (я бы называл их квантами) программируют в очень узком ключе – их в большинстве случаев не волнуют новые тренды в Asp.Net или новых языках вроде Scala или D. Они живут в совершенно другой реальности, где доминантным маст-хэв языком был, есть и будет С++. Конечно, есть варинты (например, вспомним Jane Street и их любовь к OCaml), но суть остается одна – эти разработчики привыкли работать с достаточно ограниченным tool support, и не особо от этого страдают. Ведь согласитесь, для того чтобы эффективно выполнять математические рассчеты нужно лишь чтобы у вас худо-бедно работал intellisense, и то, это не так критично если нужно вызвать что-то вроде std::min().
Соответственно, текущее положение вещей наводит на мысль, что людям которые используют в основном C++ (а также MATLAB, VBS, R, ну и другие языки на вкус) tool support как бы не очень нужен.
И все же…
Приведу конкретный пример. На многих графических устройствах, операция a*x+b оптимизирована и проходит быстрее, чем умножение и сложение отдельно. Соответственно, когда я работаю с GPU.NET, у меня есть в R2P контекстное действие, которое превращает все, что похоже на “умножение-в-сложении” на вызов вроде DeviceMath.MultiplyAdd(a, x, b). Мелочь, а приятно, и программу ускоряет.
И это далеко не частный случай. Вот еще пример – допустим что вы попросили студента за еду реализовать вам ряд формул в коде, и студент в качестве реализации написал что-то вроде y = a * Math.Pow(x, 2.0) + b * x. Бред, не так ли?
И тут снова можно включить “электронный мозг” статического анализатора и начать помогать несчастному разработчику. Для начала ему нужно объяснить, что считать ряды Тэйлора в подобном случае раз, эээ, в 50 медленнее чем сделать x*x. Но даже объяснив это, вы получите вот такой результат:
y = a * x * x + b * x;
Это тоже не очень-то эффективно. Ведь тут целых 3 умножения, хотя можно обойтись двумя:
y = x * (a * x + b);
Опаньки, а это факторизация, задачка уже посложнее, особенно в контексте статического анализа. Тем не менее, она решабельна, и позволит квонту хоть немного но ускорить вычисления.
А это имеет смысл?
Действительно, кому нужна скорость? Ну, наблюдения показывают что ряд задач (например, Монте-Карло симуляции) очень любят кушать CPU. Микрооптимизация вычислений – это как раз то, что позволит аналитику протестировать свою стратегию быстрее, на большем объеме данных.
Еще одна полезная, хотя и тривиальная вещь – это рефакторинги с уклонов в сторону параллелизации – например рефакторинг for и foreach циклов в параллельные с сохранением правильной семантики. То есть, если разработчик написал
int [] elems = new int[] { ⋮ };
int sum = 0;
foreach (var e in elems) sum += e;
то почему бы нам не дать ему возможность отрефакторить этот цикл в параллельный:
Parallel.ForEach(elems, () => 0,
(n, loopState, localSum) =>
{
localSum += n;
return localSum;
},
localSum => Interlocked.Add(ref sum, localSum));
У меня в R2P уже реализованы некоторые приведения простых циклов в параллельные, но это большая задача, и за один день ее не решить.
Другие языки?
Я привел пример поддержки C#, т.к. не знаю доступной инфраструктуры для написания рефакторингов для С++ или (это было бы еще интересней) для CUDA C. Было бы интересно услышать мнение читателей насчет применимости всех этих идей.

соль есть. только нужно наверное сразу пояснить что производительность CUDA на единичных операциях падает, ей пожалуйста большие массивы подавай, на счет тонкостей с однородностью операций сейчас не помню (это к вопросу пропускной способности шины). про умножения и математические преобразования тоже хорошо.
Dmitry Timofeev
18 Август 2011 в 23:09
То же самое относится к Parallel.ForEach. Например, параллельное умножение матриц имеет смысл только для размерностей > 30 (примерно).
Alek
19 Август 2011 в 11:18
Размерности мы сами не сможем детектировано, равно как и предстазать то, с какими параметрами вычисления будут работать быстрее всего. Но вот предоставить понятные рефакторинги для того чтобы пользователь, если ему нужно, мог перевести простой цикл в параллельный мы можем.
Dmitri
19 Август 2011 в 11:39
А откуда такая любовь к английским словам?
Теперь по сути. Для многих важно удобство работы с языком. Кванты из вашей статьи думают на с++ и это их устраивает. А переучивание приведет к тому, что они будут думать о языке, а не о задаче.
Anatoliy Sviridenkov (@anatoliy_svt)
19 Август 2011 в 3:20
14 лет прожитых в Англии дают о себе знать.
А я не предлагаю им язык менять. Просто думаю, возможно нам стоит снова задуматься о С++.
Dmitri
19 Август 2011 в 11:32
Конечно стоит:) О нем и забывать не стоило.
MS в этом плане молодцы, они на С++ не забили и сейчас VC++2010 является один из лучших компилеров native C++, с поддержкой приличного количества фич из C++ 0x (фу ты, уже можно его называть C++ 11).
Плюс, VC++2010 поддерживает ряд расширений для параллельной работы. Там же даже TPL есть, с интерфейсом очень похожим на TPL из .net framework. В общем, там очень и очень много интересного в неуправляемом мире:)
Sergey Teplyakov
19 Август 2011 в 11:57
Первое что я делаю как только начинаю работать с С++ – это заменяю Майкрософтовский стэк Интелевским. Так что конкретно в Майкровостовском С++ компиляторе я помню лишь то, что в те годы когда я усиленно штудировал книгу Generative Programming, компилятор МС не мог скомпилировать и половины из примеров в книге. В те времена были правда другие игрушки – KAI C++, Metroworks и так далее. Сейчас всем рекоммендую обратить внимание на “стэк Intel” – не только компилятор, профилятор и так далее, но также на библиотеки, в частности Math Kernel Library и Threading Building Blocks. Кстати, TBB – это как бы аналог PPL.
Dmitri
19 Август 2011 в 12:47
Сейчас, видимо, являюсь таким квонтом – много финансовой аналитики. Основной язык C#. Думаю о внедрении, хотя бы в небольших дозах(библиотеках), F#.
Это должно частично решить проблему подобных рефакторингов, дать возможность писать на более “математическом” уровне.
Т.е. о переходе на C++ и речи нет, скорее есть необходимость перевода legacy C++ кода на C#/F#.
Но для внедрения F# хотел бы найти больше информации об успешной или неуспешном опыте использоваия этого языка в финансовых вычислениях на промышленном проекте. В первую очередь, конечно, интересует скорость и удобство поддержки. Есть ли у кого-нибудь такие данные?
Alek
19 Август 2011 в 12:16
А вот эти данные вам мало кто даст. Как я написал, финансовые учреждения пока рассматривают F# как козырную карту. А карты они раскрывать не любят. С другой стороны, критика Jane Street о том что F# делает безумное кол-во аллокаций уместна, т.к. любой функциональный конструкт порождает объект. Например, если вы передаете оператор (+) как параметр, вы на самом деле создали
structкоторый этот (+) представляет.Dmitri
19 Август 2011 в 12:50
Вот и мне пока не совсем понятны козыри F# в реальном мире.
Спасибо за ответ и ссылку на Jane Street. Буду следить за их успехами, а так же за http://cufp.org/
Alexander Burdin
19 Август 2011 в 13:46