Ren
Ren

Reputation: 463

Why doesn't pow(sqrt(-1), 2) return -1?

Instead, this operation returns -1.IND, since sqrt(-1) returns -1.IND. Does the domain error mentioned on the C++ reference that this sqrt returns for negative values not retain the info that this is actually i?

Is there some way to perform this operation for all negative numbers, so that it returns the correct value, i.e. pow(sqrt(-36), 2) will return -36?

Upvotes: 9

Views: 907

Answers (5)

emsr
emsr

Reputation: 16373

If you can use C++14 you can use literal operators for complex:#include

<complex>
#include <iostream>

int
main()
{
  using namespace std::literals::complex_literals;
  auto z = std::pow(std::sqrt(-36.0 + 0.0i), 2.0);
  std::cout << z << '\n';
}

Running this I get:

ed@bad-horse:~$ ./cpow 
(-36,4.40873e-15)

I know recent gcc and clang support this. It looks like VS2015 does too.

This is actually a post-C++14 addition but it is still in a std namespace rather than experimental.

Upvotes: 0

gsamaras
gsamaras

Reputation: 73424

You can use std::complex to achieve your goal, like this:

#include <complex>
#include <iostream>

int main() {
  const std::complex<double> result = 
    std::pow(std::sqrt(std::complex<double>(-36,0)), 2);
  std::cout << result << std::endl;
  std::cout << "Real part = " << result.real() << std::endl;
}

Output:

(-36,0)
Real part = -36

Note that std::sqrt(std::complex) is used here.


The reason behind the behaviour you encountered is the signatures of sqrt, namely:

double sqrt (double x);

float sqrt (float x);

long double sqrt (long double x);

double sqrt (T x); // additional overloads for integral types

which means that no matter which prototype will be used, you are getting nothing better than a nan (or a +-inf), since the return types can not support the imaginary part. That's why std::complex exists.

So, sqrt(-1) will be replaced by a nan probably, which can not be treated by pow(), so that -1 remains intact, because of the exponent. As a result the information is already lost after the call to sqrt() and pow() can do nothing about it.

Upvotes: 13

Some programmer dude
Some programmer dude

Reputation: 409412

From this sqrt reference page:

If the argument is less than -0, FE_INVALID is raised and NaN is returned.

And then from this pow reference page

... if any argument is NaN, NaN is returned

So you simply can't use pow(sqrt(x), y) for any real x that is negative.

Upvotes: 4

dan04
dan04

Reputation: 91209

Because you're calling the function double sqrt(double), and the double return value can only store real numbers, infinity (with sign), or NaN. There is no representation for i.

If you want to store complex numbers, use std::complex.

Upvotes: 6

RedX
RedX

Reputation: 15185

std::sqrt is defined to return implementation defined error on a domain error. In this case (arg := -1) < -0 is a domain error.

std::pow is also defined to return an implementation defined error on a domain error.

So receiving -1.Ind is a plausible solution.

As Mystical pointed out you need a complex number library.

Upvotes: 3

Related Questions