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::complex
no Elemental "por várias razões". Quais são esses motivos? Quais são as vantagens e desvantagens dessa abordagem?
fonte
z
é uma expressão lvalue do tipo cvstd::complex<T>
, em seguida,reinterpret_cast<cv T(&)[2]>(z)
ereinterpret_cast<cv T(&)[2]>(z)[0]
deve designar a parte realz
, ereinterpret_cast<cv T(&)[2]>(z)[1]
deve designar a parte imagináriaz
. Matrizes de números complexos também são abordadas.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: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 .-ffast-math
std::arg
para 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 issostd::arg
teve que ser substituído poratan2(imag(),real())
. Mas foi muito fácil esquecer isso ao escrever um novo código.std::complex
usa 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.-ffast-math
sinalizador 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, causandodivision by zero
exceçõ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.-ffast-math
sinalizador 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-range
sinalizador de compilação resolva o problema, porque parece haver outro problema relacionado a-ffast-math
esta versão mais recente do gcc.-ffast-math
sinalizador de compilação torna o comportamentoNaN
completamente imprevisível para versões mais recentes do gcc (atéisnan
é afetado). A única solução alternativa parece ser evitar qualquer ocorrência deNaN
no programa, o que anula o objetivo da existência deNaN
.Agora você pode perguntar se pretendo abandonar os tipos complexos internos e
std::complex
por 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.fonte