https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90638

            Bug ID: 90638
           Summary: Wrong results of pow(complex<T> , T1) function when
                    the T1 type differs from T and from int
           Product: gcc
           Version: 4.8.5
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: Igor.Smirnov at cern dot ch
  Target Milestone: ---

Created attachment 46413
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46413&action=edit
output of "g++ -v -save-temps prog1.c"

The following program demonstrates wrong results of pow() set of functions for 
of template complex<> argument.
The comments starting from "Actually" show erroneous results:
------------------------------------------------------------------------

#include <iostream>
#include <complex>
#include <limits.h>

int main(void)
{

  double phi = M_PI / INT_MAX;
  std::complex< double > var0 = std::polar(1.0, phi);
  std::cout<<var0 << '\n';
  // Should be (1,1.46292e-09)

  int ip1 = INT_MAX;
  unsigned int ip2 = (unsigned int)ip1 + 1;
  std::cout<<ip1<<' '<<ip2<<'\n';
  // Should be 2147483647 2147483648

  std::cout<<' '<<pow(var0,  ip1)
           <<' '<<pow(var0,  ip2)
           <<'\n'<<'\n';
  // Should be (-1,7.77156e-16) (-1,-1.46292e-09)
  // Actually  (-1,7.77156e-16) (-1,1.46292e-09)


  std::complex<float> var1(2,2);
  std::cout<< sqrt(var1)
           <<'\n'<<pow(var1, float(0.5) )
           <<' '<<pow(var1, 0.5)
           <<' '<<pow(var1, (long double)(0.5) )
           <<'\n'<<'\n';
  // Should be: 
  //(1.55377,0.643594) 
  //(1.55377,0.643594) (1.55377,0.643594) (1.55377,0.643594)
  // Actually  
  //(1.55377,0.643594) 
  //(1.55377,0.643594) (1,0) (1,0)

  std::complex<double> var2(2,2);
  std::cout<< sqrt(var2)
           <<'\n'<< pow(var2, float(0.5) )
           <<' '<< pow(var2, 0.5)
           <<' '<< pow(var2, (long double)(0.5) )
           <<'\n'<<'\n';
  // Should be: 
  //(1.55377,0.643594) 
  //(1.55377,0.643594) (1.55377,0.643594) (1.55377,0.643594)
  // Actually:  
  //(1.55377,0.643594) 
  //(1,0) (1.55377,0.643594) (1,0)

  std::complex<long double> var3(2,2);
  std::cout<<sqrt(var3)
           <<'\n'<< pow(var3, float(0.5) )
           <<' '<<pow(var3, 0.5)
           <<' '<< pow(var3, (long double)(0.5) )
           <<'\n'<<'\n';
  // Should be 
  //(1.55377,0.643594) 
  //(1.55377,0.643594) (1.55377,0.643594) (1.55377,0.643594)
  // Actually  
  //(1.55377,0.643594) 
  //(1,0) (1,0) (1.55377,0.643594)


}

Here sqrt() always gives correct results and pow() correct or not depending on
the second argument.
The program is compiled by just "g++ name_of_source_file".
The identical problem was found for gcc versions 
4.8.5 (the output below is from it), 4.4.5, 4.4.7. 

The full output:

(1,1.46292e-09)
2147483647 2147483648
 (-1,7.77156e-16) (-1,1.46292e-09)

(1.55377,0.643594)
(1.55377,0.643594) (1,0) (1,0)

(1.55377,0.643594)
(1,0) (1.55377,0.643594) (1,0)

(1.55377,0.643594)
(1,0) (1,0) (1.55377,0.643594)

I think that the function pow() for the argument of "complex" template class
type is defined in such a way that with the current overload resolution of gcc
a variant of this function for the power of "int" type is called when the call
is performed with argument of any integer type (unsigned int, long and so on)
with corresponding numerical errors. 

Worse, the same pow() is also called (without any warning) for any floating
point power(!), if its type differs from the template parameter of complex<>.
The fractional part of the floating point number is discarded and the result
gets completely wrong. There is no any "call ... is ambiguous" messages, which
are usually expected, if such a problem can occur. Compilations of calls of
non-template functions in similar cases are failed with this message, but the
template functions are silently compiled. Meanwhile the user may not even know
that the functions are template.

The particular problem with powers of complex numbers based on built-in types
can be easily solved by adding in the "complex" header a set of separate
template functions for the same first argument of complex<T> type and for all
built-in types at the place of the second argument: float, double, long double
and a few more integer types. This can be done by just a few "copy-paste"
operations in a text editor with a minor additional editing, except for integer
types, since the implementation of the latter depends on the version.

The output of compilation with g++ -v -save-temps prog1.c :

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
--infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla
--enable-bootstrap --enable-shared --enable-threads=posix
--enable-checking=release --with-system-zlib --enable-__cxa_atexit
--disable-libunwind-exceptions --enable-gnu-unique-object
--enable-linker-build-id --with-linker-hash-style=gnu
--enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin
--enable-initfini-array --disable-libgcj
--with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install
--with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install
--enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64
--build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) 
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
'-march=x86-64'
 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1plus -E -quiet -v -D_GNU_SOURCE
prog1.c -mtune=generic -march=x86-64 -fpch-preprocess -o prog1.ii
ignoring nonexistent directory
"/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed"
ignoring nonexistent directory
"/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward
 /usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
 /usr/local/include
 /usr/include
End of search list.
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
'-march=x86-64'
 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1plus -fpreprocessed prog1.ii
-quiet -dumpbase prog1.c -mtune=generic -march=x86-64 -auxbase prog1 -version
-o prog1.s
GNU C++ (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-36) (x86_64-redhat-linux)
        compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-36), GMP
version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
GNU C++ (GCC) version 4.8.5 20150623 (Red Hat 4.8.5-36) (x86_64-redhat-linux)
        compiled by GNU C version 4.8.5 20150623 (Red Hat 4.8.5-36), GMP
version 6.0.0, MPFR version 3.1.1, MPC version 1.0.1
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 716696aeb8e1265fe923bf392b1dfb5e
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
'-march=x86-64'
 as -v --64 -o prog1.o prog1.s
GNU assembler version 2.27 (x86_64-redhat-linux) using BFD version version
2.27-34.base.el7
COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-save-temps' '-shared-libgcc' '-mtune=generic'
'-march=x86-64'
 /usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed
--eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker
/lib64/ld-linux-x86-64.so.2
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../.. prog1.o
-lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o

Reply via email to