Por que um cientista computacional precisaria implementar sua própria versão do std :: complex?


14

Muitas das bibliotecas C ++ mais conhecidas na ciência da computação, como Eigen , Trilinos e deal.II, usam o objeto padrão da biblioteca de cabeçalho de modelo C ++ std::complex<>, para representar números complexos de ponto flutuante.

Na resposta de Jack Poulson a uma pergunta sobre construtores padrão, ele ressalta que ele possui sua própria implementação std::complexno Elemental "por várias razões". Quais são esses motivos? Quais são as vantagens e desvantagens dessa abordagem?

Respostas:


16

Acredito que essa discussão tenha surgido várias vezes na lista do PETSc. Minhas principais razões são:

  1. O padrão C ++ afirma que std :: complex é definido apenas para os tipos de dados float, double e long double. Portanto, ele não pode ser usado para outros tipos de dados, como precisão quádrupla.

  2. O padrão não garante a estabilidade da aritmética complexa.

  3. O padrão não garante que os dados em um std :: complex sejam armazenados como o componente real seguido pelo componente imaginário. Isso é crucial para interfaces com bibliotecas externas, como BLAS e LAPACK. É verdade para todas as principais implementações, mas eu preferiria poder garantir isso.

  4. Prefiro ser capaz de manipular diretamente os componentes reais e imaginários. O std :: complex torna isso desnecessariamente difícil.

  5. Eu gostaria de, eventualmente, ter uma versão mais geral que exija apenas que o tipo de dados seja um anel em vez de exigir um campo. Isso inclui os números inteiros gaussianos.


6
O ponto 3 foi abordado no C ++ 11. 26.4.4 estados que, se zé uma expressão lvalue do tipo cv std::complex<T> , em seguida, reinterpret_cast<cv T(&)[2]>(z)e reinterpret_cast<cv T(&)[2]>(z)[0]deve designar a parte real z, e reinterpret_cast<cv T(&)[2]>(z)[1]deve designar a parte imaginária z. Matrizes de números complexos também são abordadas.
James Custer

3
@ JamesCuster: Sou a favor de eventualmente mudar para o C ++ 11, mas os códigos científicos que desejam permanecer portáteis para arquiteturas semi-exóticas provavelmente precisarão esperar pelo menos dois a três anos para fazê-lo. Além disso, infelizmente o C ++ 11 trata apenas de parte do problema.
21412 Jack Poulson

Eu entendo, eu estava lançando isso lá fora, caso alguém olhe para essa pergunta no futuro.
21812 James Custer

2
Bem, acho que é um absurdo dizer que você teria que esperar até que os compiladores suportassem o C ++ 11. O requisito explícito foi colocado no novo padrão porque todas as implementações existentes já o suportam. Não consigo pensar em um caso em que seria inseguro já assumir esse layout específico em compiladores / bibliotecas existentes, pois simplesmente não faria sentido implementar std :: complex de qualquer outra maneira.
Wolfgang Bangerth

1
@WolfgangBangerth: Foi mais um comentário geral sobre a mudança para o C ++ 11. De qualquer forma, o C ++ 11 não corrige a maioria dos problemas com o std :: complex.
22412 Jack Poulson

7

Uso std::complex<>nos meus programas e tenho que lutar com os sinalizadores do compilador e a solução alternativa para cada novo compilador ou atualização do compilador. Vou tentar recontar essas lutas em ordem cronológica:

  1. As medições de desempenho mostraram que uma etapa envolvendo apenas o cálculo do quadrado do valor absoluto de um campo de números complexos levou mais tempo que uma FFT anterior para o gcc-4.x. A escavação no código do assembler gerado mostrou que std::norm( ) calculou o valor absoluto ( ) de maneira a evitar o estouro e, em seguida, ao quadrado o resultado. Esse problema pode ser corrigido pelo sinalizador de compilação .|z|2|z|-ffast-math
  2. O compilador intel icc no linux (ou linker) compilado std::argpara um não opt em determinadas configurações (compatibilidade de link com uma versão gcc específica). O problema ressurgiu com muita frequência, por isso std::argteve que ser substituído por atan2(imag(),real()). Mas foi muito fácil esquecer isso ao escrever um novo código.
  3. O tipo std::complexusa convenções de chamada diferentes (= ABI) que o tipo complexo C99 embutido e o tipo complexo Fortran interno para versões mais recentes do gcc.
  4. O -ffast-mathsinalizador de compilação interage com o tratamento de exceções de ponto flutuante de maneiras inesperadas. O que acontece é que o compilador extrai divisões de loops, causando division by zeroexceções no tempo de execução. Essas exceções nunca teriam acontecido dentro do loop, porque a divisão correspondente não ocorreu devido à lógica circundante. Essa foi realmente péssima, porque era uma biblioteca que foi compilada separadamente do programa que usou a manipulação de exceção de ponto flutuante (usando diferentes sinalizadores de compilação) e se deparou com esses problemas (as equipes correspondentes estavam sentadas em partes opostas do mundo, então esse problema realmente causou problemas). Isso foi resolvido com a otimização usada pelo compilador manualmente com mais cuidado.
  5. A biblioteca tornou-se parte do programa e não usou mais o -ffast-mathsinalizador de compilação. Após uma atualização para uma versão mais recente do gcc, o desempenho caiu por um grande fator. Ainda não investiguei esse problema em detalhes, mas receio que esteja relacionado ao Anexo G da C99 . Devo admitir que estou completamente confuso com essa estranha definição de multiplicação para números complexos, e parece até existir versões diferentes disso com alegações de que as outras versões estão equivocadas. Espero que o -fcx-limited-rangesinalizador de compilação resolva o problema, porque parece haver outro problema relacionado a -ffast-mathesta versão mais recente do gcc.
  6. O -ffast-mathsinalizador de compilação torna o comportamento NaNcompletamente imprevisível para versões mais recentes do gcc (até isnané afetado). A única solução alternativa parece ser evitar qualquer ocorrência de NaNno programa, o que anula o objetivo da existência de NaN.

Agora você pode perguntar se pretendo abandonar os tipos complexos internos e std::complexpor esses motivos. Ficarei com os tipos internos, desde que permaneça com C ++. Caso o C ++ consiga tornar-se completamente inutilizável para a computação científica, prefiro considerar mudar para uma linguagem que cuide mais dos problemas relevantes à computação científica.


Parece que meus medos relacionados ao Anexo G do C99 se tornaram realidade, e o alcance limitado -fcx é agora necessário para uma velocidade de computação decente ao multiplicar números complexos. Pelo menos é o que recebo da seguinte história recente de guerra: medium.com/@smcallis_71148/…
Thomas Klimpel
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.