Complex mappers for real values

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Complex mappers for real values

Rik-4
All,

Does anyone know if the following comment in lo-mappers.h still applies?

// C++ now provides versions of the following functions for arguments of
// type std::complex<T> and T.  But some compilers (I'm looking at you,
// clang) apparently don't get this right yet...  So we provide our own
// wrappers for real-valued arguments.

An example of how this expands into a lot of templates is shown below:

inline double conj (double x) { return x; }
inline float conj (float x) { return x; }

template <typename T>
std::complex<T>
conj (const std::complex<T>& x)
{
  return std::conj (x);
}

According to the documentation for C++,

Additional overloads are provided for arguments of any fundamental
arithmetic type: In this case, the function assumes the value has a zero
imaginary component.
The return type is complex<double>, except if the argument is float or long
double (in which case, the return type is the complex instantiation for
that type: either complex<float> or complex<long double>).

I'd kind of be surprised if clang hasn't fixed themselves by now.

--Rik


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Dmitri A. Sergatskov


On Wed, Jun 21, 2017 at 10:40 PM, Rik <[hidden email]> wrote:
All,

Does anyone know if the following comment in lo-mappers.h still applies?

// C++ now provides versions of the following functions for arguments of
// type std::complex<T> and T.  But some compilers (I'm looking at you,
// clang) apparently don't get this right yet...  So we provide our own
// wrappers for real-valued arguments.

An example of how this expands into a lot of templates is shown below:

inline double conj (double x) { return x; }
inline float conj (float x) { return x; }

template <typename T>
std::complex<T>
conj (const std::complex<T>& x)
{
  return std::conj (x);
}

According to the documentation for C++,

Additional overloads are provided for arguments of any fundamental
arithmetic type: In this case, the function assumes the value has a zero
imaginary component.
The return type is complex<double>, except if the argument is float or long
double (in which case, the return type is the complex instantiation for
that type: either complex<float> or complex<long double>).

I'd kind of be surprised if clang hasn't fixed themselves by now.

--Rik



​If you could make a self-contained test case i can try with clang 4

Dmitri.
--

 

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

bpabbott
Administrator
On Jun 22, 2017, at 11:46 AM, Dmitri A. Sergatskov <[hidden email]> wrote:

On Wed, Jun 21, 2017 at 10:40 PM, Rik <[hidden email]> wrote:
All,

Does anyone know if the following comment in lo-mappers.h still applies?

// C++ now provides versions of the following functions for arguments of
// type std::complex<T> and T.  But some compilers (I'm looking at you,
// clang) apparently don't get this right yet...  So we provide our own
// wrappers for real-valued arguments.

An example of how this expands into a lot of templates is shown below:

inline double conj (double x) { return x; }
inline float conj (float x) { return x; }

template <typename T>
std::complex<T>
conj (const std::complex<T>& x)
{
  return std::conj (x);
}

According to the documentation for C++,

Additional overloads are provided for arguments of any fundamental
arithmetic type: In this case, the function assumes the value has a zero
imaginary component.
The return type is complex<double>, except if the argument is float or long
double (in which case, the return type is the complex instantiation for
that type: either complex<float> or complex<long double>).

I'd kind of be surprised if clang hasn't fixed themselves by now.

--Rik

​If you could make a self-contained test case i can try with clang 4

Dmitri.

I’m happy to test Apple’s clang as well.

clang -v
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix

Ben


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Mike Miller-4
In reply to this post by Rik-4
On Wed, Jun 21, 2017 at 20:40:14 -0700, Rik wrote:
> Does anyone know if the following comment in lo-mappers.h still applies?
>
> // C++ now provides versions of the following functions for arguments of
> // type std::complex<T> and T.  But some compilers (I'm looking at you,
> // clang) apparently don't get this right yet...  So we provide our own
> // wrappers for real-valued arguments.

I would be surprised if it *didn't* still apply. This change was made
only 10 months ago, in response to the following thread:

  https://lists.gnu.org/archive/html/octave-maintainers/2016-08/msg00089.html

--
mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Mike Miller-4
In reply to this post by Rik-4
On Wed, Jun 21, 2017 at 20:40:14 -0700, Rik wrote:
> // C++ now provides versions of the following functions for arguments of
> // type std::complex<T> and T.  But some compilers (I'm looking at you,
> // clang) apparently don't get this right yet...  So we provide our own
> // wrappers for real-valued arguments.

Actually it may be more accurate to say that clang has the correct
prototype, gcc does not.

According to cppreference [1], std::conj(double) should return a
std::complex<double>. Under gcc's libstdc++, the return value is a
double. Using clang's libc++, the return value is a
std::complex<double>.

Octave wants the conj function to return the same type that was passed
in, which disagrees with the C++ specification.

This may be a peculiarity of conj, the other functions mentioned do
return the same type that they were passed, either complex or
non-complex. Is it clearer to have an adapter only for conj and leave
out the others? Or to provide all of them in liboctave for symmetry?

--
mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Mike Miller-4
On Thu, Jun 22, 2017 at 10:14:26 -0700, Mike Miller wrote:
> According to cppreference [1], std::conj(double) should return a
> std::complex<double>. Under gcc's libstdc++, the return value is a
> double. Using clang's libc++, the return value is a
> std::complex<double>.

I forgot the link

  [1] http://en.cppreference.com/w/cpp/numeric/complex/conj

Might as well share these for comparison

  [2] http://en.cppreference.com/w/cpp/numeric/complex/arg
  [3] http://en.cppreference.com/w/cpp/numeric/complex/imag
  [4] http://en.cppreference.com/w/cpp/numeric/complex/real

To repeat and clarify, I suspect std::arg, std::imag, and std::real are
ok to use directly, but std::conj differs between compilers, and Octave
wants behavior that differs from the C++ standard anyway.

HTH,

--
mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Dmitri A. Sergatskov
On Thu, Jun 22, 2017 at 12:30 PM, Mike Miller <[hidden email]> wrote:
On Thu, Jun 22, 2017 at 10:14:26 -0700, Mike Miller wrote:
> According to cppreference [1], std::conj(double) should return a
> std::complex<double>. Under gcc's libstdc++, the return value is a
> double. Using clang's libc++, the return value is a
> std::complex<double>.

I forgot the link

  [1] http://en.cppreference.com/w/cpp/numeric/complex/conj

using sample code with
​gcc-4.8.5/gcc-7.1.1/clang-4.0.0 (with either libc++ or libstdc++) all give
the same (correct) answer.

If I use Carnë Draug's code from the old thread

https://lists.gnu.org/archive/html/octave-maintainers/2016-08/msg00090.html

cat t1.cc
    #include <iostream>
    #include <complex>
    #include <typeinfo>

    int main()
    {
      std::cout << typeid (std::conj (double (5.0))).name() << std::endl;
    }


gcc-4.8.5 returns
g++ -std=c++11 t1.cc
d

(gcc 7.1.1)  g++ t1.cc
./a.out
St7complexIdE

(clang 4.0.0)
clang++ -std=c++11 t1.cc
./a.out
St7complexIdE

clang++ -std=c++11 -stdlib=libc++ t1.cc
./a.out
NSt3__17complexIdEE

Not sure how it is all relevent, but just fyi.

--
mike


​Dmitri.
--

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Mike Miller-4
On Thu, Jun 22, 2017 at 12:47:49 -0500, Dmitri A. Sergatskov wrote:
> using sample code with
> gcc-4.8.5/gcc-7.1.1/clang-4.0.0 (with either libc++ or libstdc++) all give
> the same (correct) answer.

Hm? They give different answers:

> gcc-4.8.5 returns
> g++ -std=c++11 t1.cc
> d
>
> (gcc 7.1.1)  g++ t1.cc
> ./a.out
> St7complexIdE

So std::conj has been fixed in gcc 7.

With gcc 6, it still returns a double.

Octave wants conj to return a double, so it looks like it should
continue to use the octave::math::conj adapter.

--
mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Dmitri A. Sergatskov


On Thu, Jun 22, 2017 at 1:01 PM, Mike Miller <[hidden email]> wrote:
On Thu, Jun 22, 2017 at 12:47:49 -0500, Dmitri A. Sergatskov wrote:
> using sample code with
> gcc-4.8.5/gcc-7.1.1/clang-4.0.0 (with either libc++ or libstdc++) all give
> the same (correct) answer.

Hm? They give different answers:

​I meant the code from
http://en.cppreference.com/w/cpp/numeric/complex/conj

#include <iostream>
#include <complex>
 
int main()
{
    std::complex<double> z(1,2);
    std::cout << "The conjugate of " << z << " is " << std::conj(z) << '\n'
              << "Their product is " << z*std::conj(z) << '\n';
}

​returns the same with all compilers I tried:

​The conjugate of (1,2) is (1,-2)
Their product is (5,0)


​But ​Carnë Draug's code has a discrepancies.

 

> gcc-4.8.5 returns
> g++ -std=c++11 t1.cc
> d
>
> (gcc 7.1.1)  g++ t1.cc
> ./a.out
> St7complexIdE

So std::conj has been fixed in gcc 7.

With gcc 6, it still returns a double.

​I found a computer with gcc 6.3.1 and it does return "d".​

 

Octave wants conj to return a double, so it looks like it should
continue to use the octave::math::conj adapter.

--
mike


​Dmitri.
--

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Mike Miller-4
On Thu, Jun 22, 2017 at 13:14:58 -0500, Dmitri A. Sergatskov wrote:
> I meant the code from
>
> http://en.cppreference.com/w/cpp/numeric/complex/conj
[…]
> returns the same with all compilers I tried:
>
> The conjugate of (1,2) is (1,-2)
> Their product is (5,0)

Ok, no surprise there.

> But Carnë Draug's code has a discrepancies.

Right. And thanks for that pointer (and thanks Carnë for pointing to the
WG discussion), that helps clarify that this may be considered a bug in
the C++11 standard and may have changed or may change in subsequent
revisions of the standard.

For now, to support gcc 4.8-7 and clang, we must continue to provide our
own conj wrapper.

Rik - I feel like the comment could be worded better to clarify that
this is a defect in the C++11 standard wording and compilers have chosen
to impement this differently and all may change in the future… but for
now we must keep at least the conj wrapper.

--
mike

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Complex mappers for real values

Rik-4
On 06/22/2017 11:48 AM, Mike Miller wrote:

> On Thu, Jun 22, 2017 at 13:14:58 -0500, Dmitri A. Sergatskov wrote:
>> I meant the code from
>>
>> http://en.cppreference.com/w/cpp/numeric/complex/conj
> […]
>> returns the same with all compilers I tried:
>>
>> The conjugate of (1,2) is (1,-2)
>> Their product is (5,0)
> Ok, no surprise there.
>
>> But Carnë Draug's code has a discrepancies.
> Right. And thanks for that pointer (and thanks Carnë for pointing to the
> WG discussion), that helps clarify that this may be considered a bug in
> the C++11 standard and may have changed or may change in subsequent
> revisions of the standard.
>
> For now, to support gcc 4.8-7 and clang, we must continue to provide our
> own conj wrapper.
>
> Rik - I feel like the comment could be worded better to clarify that
> this is a defect in the C++11 standard wording and compilers have chosen
> to impement this differently and all may change in the future… but for
> now we must keep at least the conj wrapper.

I will keep the conj wrapper.

I prefer less code to more code because there is a maintenance burden for
every single line.  I'll remove the other complex wrapper functions.

--Rik



Loading...