简体   繁体   中英

How to use boost::compute::atan2?

I would like to compute the phase of a complex number using boost::compute

here is my attempt, I expect the result to be equal to atan2(0.5f):

namespace bc = boost::compute;

bc::vector<std::complex<float>> vec{ {1.0f, 2.0f} };
bc::vector<float> result(1);
bc::transform(vec.begin(), vec.end(), result.begin(), bc::atan2<float>());

but I get a compilation error claiming "Non-unary function invoked one argument"

boost::compute 's atan2 would appear to be a binary function just like std::atan2 .

I'm assuming you're trying to obtain the phase angle of your complex number? The standard C++ function for this would be std::arg() - I don't see this one being defined in boost::compute , though I might have missed it.

If arg() is indeed missing, you're quite right it's implemented via atan2 - you'll need to extract the imaginary ( boost::compute::imag() ) and real ( boost::compute::real() ) components first though, and pass them as individual arguments to atan2 .

I found a way to make it work.

stage 1: allocate 2 vectors:

bc::vector<std::complex<float>> vec{ {1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f} };
bc::vector<float> result(3);

stage 2: interpret the complex vector as a float buffer iterator

buffer_iterator is quite useful when you have a strongly typed vector and would like to pass it to an algorithm as a different type.

auto beginf = bc::make_buffer_iterator<float>(vec.get_buffer(), 0);
auto endf = bc::make_buffer_iterator<float>(vec.get_buffer(), 6); // note end point to final index + 1

stage 3: define strided iterators so that we can use the same buffer as the argument for tan2. each iterator iterates the buffers in strides of 2 indices, and they supply tan2 with interleaved access to the buffer:

auto begin_a = bc::make_strided_iterator(beginf + 1, 2); // access imaginary part
auto end_a = bc::make_strided_iterator_end(beginf + 1, endf , 2);
auto begin_b = bc::make_strided_iterator(beginf, 2); // access real part

finally, call transform:

bc::transform(begin_a, end_a, begin_b, result.begin(), bc::atan2<float>()); // atan(b/a)
bc::system::default_queue().finish();

I think you can also use Boost.Compute's lambda expressions for this:

  bc::vector<float2> input{ {1.0f, 2.0f}, {3.0f, 4.0f}, {5.0f, 6.0f} };
  bc::vector<float> output(3); 

  using boost::compute::lambda::atan2;
  using boost::compute::_1;
  using boost::compute::lambda::get;

  bc::transform(
    float2_input.begin(),
    float2_input.end(),
    float_output.begin(),
    atan2(get<1>(_1), get<0>(_1)),
    queue
  );

float2 is bassically a complex in Boost.Compute. You can also check test_lambda.cpp .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM