std::norm von std::complex benutzt std::sqrt????



  • Ich habe Performance-Messungen angestellt und herausgefunden, warum std::complex<double> meinen Algorithmus langsam macht.

    Es geht um die Funktion std::norm(c) , die eigentlich nichts anderes als c.real()*c.real() + c.imag()*c.imag() berechnet (des Quadrat der euklidischen Norm halt). Aus der Doku:

    <a href= schrieb:

    http://en.cppreference.com/w/cpp/numeric/complex/norm">The norm calculated by this function is also known as field norm or absolute square.

    The Euclidean norm of a complex number is provided by std::abs , which is more costly to compute. In some situations, it may be replaced by std::norm , for example, if abs(z1) > abs(z2) then norm(z1) > norm(z2) .

    Aus der Standardbibliothek vom GCC:

    // 26.2.7/5: norm(__z) returns the squared magnitude of __z.
      //     As defined, norm() is -not- a norm is the common mathematical
      //     sense used in numerics.  The helper class _Norm_helper<> tries to
      //     distinguish between builtin floating point and the rest, so as
      //     to deliver an answer as close as possible to the real value.
      template<bool>
        struct _Norm_helper
        {
          template<typename _Tp>
            static inline _Tp _S_do_it(const complex<_Tp>& __z)
            {
              const _Tp __x = __z.real();
              const _Tp __y = __z.imag();
              return __x * __x + __y * __y;
            }
        };
    
      template<>
        struct _Norm_helper<true>
        {
          template<typename _Tp>
            static inline _Tp _S_do_it(const complex<_Tp>& __z)
            {
              _Tp __res = std::abs(__z);
              return __res * __res;
            }
        };
    
      template<typename _Tp>
        inline _Tp
        norm(const complex<_Tp>& __z)
        {
          return _Norm_helper<__is_floating<_Tp>::__value 
            && !_GLIBCXX_FAST_MATH>::_S_do_it(__z);
        }
    
    // ...
    
      // 26.2.7/3 abs(__z):  Returns the magnitude of __z.
      template<typename _Tp>
        inline _Tp
        __complex_abs(const complex<_Tp>& __z)
        {
          _Tp __x = __z.real();
          _Tp __y = __z.imag();
          const _Tp __s = std::max(abs(__x), abs(__y));
          if (__s == _Tp())  // well ...
            return __s;
          __x /= __s; 
          __y /= __s;
          return __s * sqrt(__x * __x + __y * __y);
        }
    
    // ...
    
      template<typename _Tp>
        inline _Tp
        abs(const complex<_Tp>& __z) { return __complex_abs(__z); }
    

    Mit anderen Worten, es werden zahlreiche Checks durchgeführt, unter anderem die Wurzel gezogen und am Schluss wieder quadriert.

    Was soll das? Wer würde das je wollen? Wie schalte ich das ab? IEEE-Kompatibilität ist mir wichtig, deshalb kommt es für mich nicht in Frage, mit --ffast-math zu kompilieren. Das Makro _GLIBCXX_FAST_MATH ist leider nicht dafür vorgesehen, vom Benutzer gesetzt zu werden, da es im config-Header gesetzt wird.



  • Eigentlich könnte mir das egal sein, da ich norm selten direkt verwende und mir eine eigene Funktion schreiben könnte.

    Aber operator/ benutzt norm . Und den brauche ich!


  • Mod

    Allein schon ein
    Google: std::norm gcc
    beantwortet die Frage. Die Begründungen sind mir zwar fadenscheinig, aber so ist nun einmal der Stand der Dinge. Gut zu wissen, dann werde ich die GCC-Implementierung in Zukunft selber auch vermeiden.

    baukomplex schrieb:

    Eigentlich könnte mir das egal sein, da ich norm selten direkt verwende und mir eine eigene Funktion schreiben könnte.

    Aber operator/ benutzt norm . Und den brauche ich!

    Dann musst du eben auch eine eigene Funktion dafür schreiben.



  • SeppJ schrieb:

    Allein schon ein
    Google: std::norm gcc
    beantwortet die Frage. Die Begründungen sind mir zwar fadenscheinig, aber so ist nun einmal der Stand der Dinge.

    Sorry, Filterblase!
    Mir zeigt google ganz andere Sachen als Dir und auf der ersten Seite ist kein Link, der irgendwie zu Deinem Text passt. Möglicherweise wäre es eventuell unter Umständen manchmal keine völlig absurde Idee, in nichttrivialen Fällen das Linkziel statt der Suchanfrage zu posten.

    Der GCC-Weg ist eigentlich, Oberkacke in die stdlib zu schreiben und dann den Compiler daraufhin anzupassen, daß er die Oberkacke wegoptimiert bzw nicht anwarnt.


  • Mod

    Nanu? Ich war mir eigentlich recht sicher, die Filterblase ausgeschaltet zu haben. Relevante Ergebnisse:
    http://www.programdoc.com/1094_43623_1.htm
    https://gcc.gnu.org/ml/gcc-patches/2009-03/msg00197.html



  • SeppJ schrieb:

    Nanu? Ich war mir eigentlich recht sicher, die Filterblase ausgeschaltet zu haben. Relevante Ergebnisse:
    http://www.programdoc.com/1094_43623_1.htm
    https://gcc.gnu.org/ml/gcc-patches/2009-03/msg00197.html

    Der programdoc-Link kommt bei mir erst ganz unten auf der zweiten Seite, so weit schaue ich nie.

    Die paar Begründungen (die für mich eher nach wilden Vermutungen tönen) nützen mir ausserdem nichts, ich will Lösungen.

    Ist einen eigenen complex schreiben das beste, was ich machen kann?


Log in to reply