Зачем ученому в области вычислительной техники реализовать собственную версию std :: complex?

14

Многие из наиболее известных библиотек C ++ в вычислительной науке, такие как Eigen , Trilinos и deal.II, используют стандартный объект библиотеки заголовков шаблонов C ++ std::complex<>для представления сложных чисел с плавающей запятой.

В ответе Джека Полсона на вопрос о конструкторах по умолчанию он указывает, что у него есть своя реализация std::complexв Elemental «по ряду причин». Каковы эти причины? Каковы преимущества и недостатки этого подхода?

Арон Ахмадия
источник

Ответы:

16

Я считаю, что это обсуждение неоднократно встречалось в списке PETSc. Мои основные причины:

  1. Стандарт C ++ гласит, что std :: complex определен только для типов данных float, double и long double. Таким образом, он не может использоваться для других типов данных, таких как четверная точность.

  2. Стандарт не дает никаких гарантий относительно устойчивости сложной арифметики.

  3. Стандарт не гарантирует, что данные в std :: complex хранятся как реальный компонент, за которым следует мнимый компонент. Это очень важно для интерфейсов с внешними библиотеками, такими как BLAS и LAPACK. Это верно для всех основных реализаций, но я бы предпочел быть в состоянии обеспечить это.

  4. Я предпочитаю иметь возможность напрямую манипулировать реальными и воображаемыми компонентами. std :: complex делает это излишне сложным.

  5. Я хотел бы в конечном итоге иметь более общую версию, которая требует, чтобы тип данных был кольцом, а не полем. Это будет включать гауссовы целые числа.

Джек Полсон
источник
6
Пункт 3 был рассмотрен в C ++ 11. 26.4.4 утверждает, что если zявляется выражением lvalue типа cv, std::complex<T> то reinterpret_cast<cv T(&)[2]>(z)и reinterpret_cast<cv T(&)[2]>(z)[0]должно обозначать действительную часть z, и reinterpret_cast<cv T(&)[2]>(z)[1]должно обозначать мнимую часть z. Массивы комплексных чисел также адресуются.
Джеймс Кастер
3
@JamesCuster: Я в конечном итоге за переход на C ++ 11, но научным кодам, которые хотят оставаться переносимыми на полуэкзотические архитектуры, вероятно, придется подождать еще как минимум два-три года, чтобы сделать это. Кроме того, C ++ 11, к сожалению, решает только часть проблемы.
Джек Поулсон
Я понимаю, я просто выбросил это на тот случай, если кто-нибудь рассмотрит этот вопрос в будущем.
Джеймс Кастер
2
Ну, я думаю, что это отговорка, чтобы сказать, что вам придется подождать, пока компиляторы не поддержат C ++ 11. Явное требование было введено в новый стандарт, потому что все существующие реализации уже поддерживают его. Я не могу вспомнить случай, когда было бы небезопасно уже предполагать этот конкретный макет в существующих компиляторах / библиотеках, поскольку просто не имело бы никакого смысла реализовывать std :: complex любым другим способом.
Вольфганг Бангерт
1
@WolfgangBangerth: Это был скорее общий комментарий по переходу на C ++ 11. В любом случае, C ++ 11 не решает большинство проблем с std :: complex.
Джек Полсон,
7

я использую std::complex<> в своих программах, и мне приходится бороться с флагами компилятора и обходным путем для каждого нового обновления компилятора или компилятора. Я постараюсь перечислить эти бои в хронологическом порядке:

  1. Измерения производительности показали, что этап, включающий только вычисление квадрата абсолютного значения поля комплексных чисел, занимает больше времени, чем предыдущий FFT для gcc-4.x. Копание в сгенерированном ассемблерном коде показало, что std::norm(|Z|2) вычислили абсолютное значение (|Z|) таким образом, чтобы избежать переполнения, а затем возвести в квадрат результат. Эта проблема может быть исправлена ​​с помощью флага компиляции -ffast-math.
  2. Компилятор intel icc на linux (или компоновщике) скомпилирован std::argдля non-opt при определенных конфигурациях (совместимость ссылок с определенной версией gcc). Проблема всплывала слишком часто, поэтому std::argпришлось заменить на atan2(imag(),real()). Но было слишком легко забыть об этом при написании нового кода.
  3. Тип std::complexиспользует другие соглашения о вызовах (= ABI), чем встроенный комплексный тип C99, и встроенный комплексный тип Fortran для более новых версий gcc.
  4. В -ffast-mathкомпиляции флаг взаимодействует с обработкой с плавающей точкой исключения неожиданным образом. Что происходит, так это то, что компилятор вытягивает деления из циклов, вызывая тем самымdivision by zero исключения во время выполнения. Эти исключения никогда бы не произошли внутри цикла, потому что соответствующее деление не произошло из-за окружающей логики. Это было действительно плохо, потому что это была библиотека, которая была скомпилирована отдельно от программы, которая использовала обработку исключений с плавающей запятой (используя разные флаги компиляции) и сталкивалась с этими проблемами (соответствующие команды сидели в разных частях света, поэтому эта проблема действительно вызвала неприятности). Это было решено путем более тщательной оптимизации, используемой компилятором вручную.
  5. Библиотека стала частью программы и больше не использовала -ffast-mathфлаг компиляции. После обновления до более новой версии gcc производительность сильно упала. Я еще детально не исследовал эту проблему, но боюсь, что она связана с Приложением G C99 . Я должен признать, что я совершенно смущен этим странным определением умножения для комплексных чисел, и даже кажется, что существуют разные версии этого с утверждениями, что другие версии ошибочны. Я надеюсь, что -fcx-limited-rangeфлаг компиляции решит проблему, потому что, похоже, есть еще одна проблема, связанная с -ffast-mathэтой более новой версией gcc.
  6. -ffast-mathФлаг компиляции делает поведение NaNсовершенно непредсказуемым для новых версий GCC (даже isnanпораженный). Единственный обходной путь, по-видимому, состоит в том, чтобы избежать любого вхождения NaNв программе, что противоречит цели существования NaN.

Теперь вы можете спросить, планирую ли я отказаться от встроенных сложных типов и std::complexпо этим причинам. Я останусь со встроенными типами, пока я остаюсь с C ++. В случае, если C ++ станет полностью непригодным для научных вычислений, я бы предпочел перейти на язык, который больше заботится о проблемах, связанных с научными вычислениями.

Томас Климпел
источник
Похоже, мои опасения, связанные с Приложением G C99, сбылись, и -fcx-limited-range теперь как бы необходим для приличной скорости вычислений при умножении комплексных чисел. По крайней мере, это то, что я получаю из следующей недавней военной истории: medium.com/@smcallis_71148/…
Томас Климпел