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