Topic: Complex pow() template instantiation concerns
Author: eggplantparts@yahoo.com (Jim West)
Date: Fri, 9 Jan 2004 18:20:08 +0000 (UTC) Raw View
A recent thread on comp.lang.c++ revealed some rather surprising
behavior of the pow() function included in the <std::complex> header.
The following code
#include <complex>
#include <iostream>
int main() {
std::complex<float> Minus_One(-1.0, 0.0);
std::complex<float> Should_Be_Imaginary_One = std::pow(Minus_One, 0.5);
std::cout << Should_Be_Imaginary_One << std::endl;
}
actually gives an output of (1, 0) rather than the (0, 1) desired on
standard conforming compilers. In the post
<http://groups.google.com/groups?q=g:thl3115266325d&dq=&hl=en&lr=&ie=UTF-8&selm=VE6Lb.49998%24nG3.24912%40twister.socal.rr.com>
CrayzeeWulf diagnosed the problem. The standard lists four different
pow() template functions in <complex>:
1. template<class T>
complex<T> pow( const complex<T>& x, int y) ;
2. template<class T>
complex<T> pow( const complex<T>& x, const complex<T>& y) ;
3. template<class T>
complex<T> pow( const complex<T>& x, const T& y) ;
4. template<class T>
complext<T> pow( const T& x, const complex<T>& y ) ;
Following the standard rules for template instantiation,
template 1 is
selected with the double constant 0.5 being demoted to int 0,
giving an
incorrect (or at least highly unexpected) mathematical answer. This
behavior is repeated for any mismatched precision between the complex
and floating point arguments (such as sending complex<long double> and
and double arguments, as the original poster did in the other thread ),
and is true for any complex number.
I find this to be a potentially very serious problem in the standard
library definition of the complex pow() function for numerical programmers
who don't have an intimate knowledge of the C++ language. Many of us
have Fortran (or other similar languages) backgrounds where 0.5 is
a single precision constant. pow(complex<float>(2.1, 4.3), 3.38484) looks
"right",
and the fact that it would lead to an incorrect answer without
warning is very counter-intuitive. Prior to seeing the other thread it
would never have occured to me that 3.38484 would be truncated to 3. I
would not be at all surprised if there are numerous programs out there
that unknowingly have bugs resulting from this behavior. (The GNU
3.3.2 compiler is the exception I have seen that provides a warning on
truncating the floating point constant, but the Intel C++ 8.0 did not,
and apparently Visual C++ that the original poster used did not.)
Is this something that the C++ standards committee would like to know
about? If so,
what should I do to a) learn if they are already addressing
it and b) make them aware if they are not?
Actually, all compilers giving a strong warning when a floating point
value is truncated to int in a template instantiation would probably be
sufficient (as the GNU compiler does), and would probably find a lot more
similar bugs.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pjp@dinkumware.com ("P.J. Plauger")
Date: Mon, 12 Jan 2004 17:49:25 +0000 (UTC) Raw View
"Jim West" <eggplantparts@yahoo.com> wrote in message
news:slrnbvtip0.jl7.eggplantparts@emag.ecen.okstate.edu...
> A recent thread on comp.lang.c++ revealed some rather surprising
> behavior of the pow() function included in the <std::complex> header.
> The following code
>
>
> #include <complex>
> #include <iostream>
>
> int main() {
> std::complex<float> Minus_One(-1.0, 0.0);
> std::complex<float> Should_Be_Imaginary_One = std::pow(Minus_One, 0.5);
> std::cout << Should_Be_Imaginary_One << std::endl;
> }
>
>
> actually gives an output of (1, 0) rather than the (0, 1) desired on
> standard conforming compilers. In the post
>
<http://groups.google.com/groups?q=g:thl3115266325d&dq=&hl=en&lr=&ie=UTF-8&s
elm=VE6Lb.49998%24nG3.24912%40twister.socal.rr.com>
> CrayzeeWulf diagnosed the problem. The standard lists four different
> pow() template functions in <complex>:
>
> 1. template<class T>
> complex<T> pow( const complex<T>& x, int y) ;
>
> 2. template<class T>
> complex<T> pow( const complex<T>& x, const complex<T>& y) ;
>
> 3. template<class T>
> complex<T> pow( const complex<T>& x, const T& y) ;
>
> 4. template<class T>
> complext<T> pow( const T& x, const complex<T>& y ) ;
>
> Following the standard rules for template instantiation,
> template 1 is
> selected with the double constant 0.5 being demoted to int 0,
> giving an
> incorrect (or at least highly unexpected) mathematical answer. This
> behavior is repeated for any mismatched precision between the complex
> and floating point arguments (such as sending complex<long double> and
> and double arguments, as the original poster did in the other thread ),
>
> and is true for any complex number.
>
> I find this to be a potentially very serious problem in the standard
> library definition of the complex pow() function for numerical programmers
> who don't have an intimate knowledge of the C++ language. Many of us
> have Fortran (or other similar languages) backgrounds where 0.5 is
> a single precision constant. pow(complex<float>(2.1, 4.3), 3.38484) looks
> "right",
> and the fact that it would lead to an incorrect answer without
> warning is very counter-intuitive. Prior to seeing the other thread it
> would never have occured to me that 3.38484 would be truncated to 3. I
> would not be at all surprised if there are numerous programs out there
> that unknowingly have bugs resulting from this behavior. (The GNU
> 3.3.2 compiler is the exception I have seen that provides a warning on
> truncating the floating point constant, but the Intel C++ 8.0 did not,
> and apparently Visual C++ that the original poster used did not.)
>
> Is this something that the C++ standards committee would like to know
> about? If so,
> what should I do to a) learn if they are already addressing
> it and b) make them aware if they are not?
>
> Actually, all compilers giving a strong warning when a floating point
> value is truncated to int in a template instantiation would probably be
> sufficient (as the GNU compiler does), and would probably find a lot more
> similar bugs.
We know about it. In fact, we're even doing something about it. The
committee is developing a (non-normative) Technical Report that adds
*lots* of stuff to the Standard C++ library. One great chunk of this
stuff includes all the math functions added with C99. And a serious
chunk of this chunk is a bunch of overloads for the math functions
to make overload resolution more closely match the ancient Fortran
rules. (You get the same results with the type generic macros in the
C99 header <tgmath.h>.)
pow happens to be a special case, because C++ adds pow(T, int)
overloads for T any real or complex type. Nevertheless, it still
benefits from these extra overloads. The problem that began the
original thread would, for example, go away.
We've had these extra overloads in the Dinkumware C++ library
for the past year or so, and they don't seem to cause any
problems. Putting them in the library TR will give even more
people experience with this approach. So there's a good chance
the problem will disappear with a future revision of the C++
Standard.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: NOSPAMsjhowe@dial.pipex.com ("Stephen Howe")
Date: Tue, 13 Jan 2004 18:10:53 +0000 (UTC) Raw View
> #include <complex>
> #include <iostream>
>
> int main() {
> std::complex<float> Minus_One(-1.0, 0.0);
> std::complex<float> Should_Be_Imaginary_One = std::pow(Minus_One, 0.5);
> std::cout << Should_Be_Imaginary_One << std::endl;
> }
Do your compilers select the a different template if the constants are
suffixed with F ?
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: eggplantparts@yahoo.com (Jim West)
Date: Wed, 14 Jan 2004 04:35:11 +0000 (UTC) Raw View
In article <40042f7b$0$9383$ed9e5944@reading.news.pipex.net>,
"Stephen Howe" wrote:
>> #include <complex>
>> #include <iostream>
>>
>> int main() {
>> std::complex<float> Minus_One(-1.0, 0.0);
>> std::complex<float> Should_Be_Imaginary_One = std::pow(Minus_One, 0.5);
>> std::cout << Should_Be_Imaginary_One << std::endl;
>> }
>
> Do your compilers select the a different template if the constants are
> suffixed with F ?
>
> Stephen Howe
Yes. As long as the precisions of the complex and real arguments of the
pow() function are the same it chooses the intended template, and gives
the expected output of (0.0, 1.0).
Jim
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]