Commit 4f75543d by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/61761 fix std::proj for targets without C99 cproj

The current generic implementation of __complex_proj used when cproj is
not available calculates the wrong projection, giving a different result
than given by C99's cproj.

When C99 cproj is not available but isinf and copysign are, use those to
give correct results for float, double and long double. Otherwise, and
for other specializations of std::complex, just use a generic version
that returns its argument, and so doesn't support infinities.

We might want to consider adding additional overloads of __complex_proj
to support extended types such as _Float64x, _Float128 etc.

	PR libstdc++/61761
	* include/std/complex (__complex_proj): Return parameter unchanged.
	[_GLIBCXX_USE_C99_COMPLEX] (__complex_proj): Change overloads for
	floating-point types to take std::complex arguments.
	[_GLIBCXX_USE_C99_MATH_TR1] (__complex_proj): Add overloads for
	floating-point types.
	* testsuite/26_numerics/complex/proj.cc: New test.

From-SVN: r270759
parent 4f475391
2019-05-01 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/61761
* include/std/complex (__complex_proj): Return parameter unchanged.
[_GLIBCXX_USE_C99_COMPLEX] (__complex_proj): Change overloads for
floating-point types to take std::complex arguments.
[_GLIBCXX_USE_C99_MATH_TR1] (__complex_proj): Add overloads for
floating-point types.
* testsuite/26_numerics/complex/proj.cc: New test.
2019-04-30 Jakub Jelinek <jakub@redhat.com>
* config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Change _Lock_policyE2 exports
......
......@@ -1898,41 +1898,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp>
std::complex<_Tp> proj(const std::complex<_Tp>&);
// Generic implementation of std::proj, does not work for infinities.
template<typename _Tp>
std::complex<_Tp>
inline std::complex<_Tp>
__complex_proj(const std::complex<_Tp>& __z)
{
const _Tp __den = (__z.real() * __z.real()
+ __z.imag() * __z.imag() + _Tp(1.0));
return std::complex<_Tp>((_Tp(2.0) * __z.real()) / __den,
(_Tp(2.0) * __z.imag()) / __den);
}
{ return __z; }
#if _GLIBCXX_USE_C99_COMPLEX
inline __complex__ float
__complex_proj(__complex__ float __z)
{ return __builtin_cprojf(__z); }
inline __complex__ double
__complex_proj(__complex__ double __z)
{ return __builtin_cproj(__z); }
inline __complex__ long double
__complex_proj(const __complex__ long double& __z)
{ return __builtin_cprojl(__z); }
inline complex<float>
__complex_proj(const complex<float>& __z)
{ return __builtin_cprojf(__z.__rep()); }
inline complex<double>
__complex_proj(const complex<double>& __z)
{ return __builtin_cproj(__z.__rep()); }
inline complex<long double>
__complex_proj(const complex<long double>& __z)
{ return __builtin_cprojl(__z.__rep()); }
#elif defined _GLIBCXX_USE_C99_MATH_TR1
inline complex<float>
__complex_proj(const complex<float>& __z)
{
if (__builtin_isinf(__z.real()) || __builtin_isinf(__z.imag()))
return complex<float>(__builtin_inff(),
__builtin_copysignf(0.0f, __z.imag()));
return __z;
}
inline complex<double>
__complex_proj(const complex<double>& __z)
{
if (__builtin_isinf(__z.real()) || __builtin_isinf(__z.imag()))
return complex<double>(__builtin_inf(),
__builtin_copysign(0.0, __z.imag()));
return __z;
}
inline complex<long double>
__complex_proj(const complex<long double>& __z)
{
if (__builtin_isinf(__z.real()) || __builtin_isinf(__z.imag()))
return complex<long double>(__builtin_infl(),
__builtin_copysignl(0.0l, __z.imag()));
return __z;
}
#endif
template<typename _Tp>
inline std::complex<_Tp>
proj(const std::complex<_Tp>& __z)
{ return __complex_proj(__z.__rep()); }
#else
template<typename _Tp>
inline std::complex<_Tp>
proj(const std::complex<_Tp>& __z)
{ return __complex_proj(__z); }
#endif
// Overload for scalars
template<typename _Tp>
inline std::complex<typename __gnu_cxx::__promote<_Tp>::__type>
proj(_Tp __x)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment