Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::sqrt(std::complex<T>) produces incorrect results for large real components #122172

Open
cjdb opened this issue Jan 8, 2025 · 1 comment
Open
Assignees
Labels
confirmed Verified by a second party floating-point Floating-point math libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Comments

@cjdb
Copy link
Contributor

cjdb commented Jan 8, 2025

The following program produces an incorrect complex value due to floating-point numbers being unable to store a precise enough angle when converting to polar values.

template<class T>
void sqrt()
{
  auto const x = std::complex<T>{std::numeric_limits<float>::lowest(), 1.0f};
  std::println("x = {} + i * {}", x.real(), x.imag());
  auto const s = std::sqrt(x);
  std::println("sqrt(x) = {} + i * {}", s.real(), s.imag());
}

int main()
{
  std::println("==== expected ====");
  std::println("x = {} + i * {}", std::numeric_limits<float>::lowest(), 1.0f);
  std::println("sqrt(x) = 2.7105055e-20 + i * 1.8446744e19");

  std::println("==== sqrt<float>() ====");
  sqrt<float>();

  std::println("==== sqrt<double>() ====");
  sqrt<double>();
  
  std::println("==== sqrt<long double>() ====");
  sqrt<long double>();
}
==== expected ====
x = -3.4028235e+38 + i * 1
sqrt(x) = 2.7105055e-20 + i * 1.8446744e19
==== sqrt<float>() ====
x = -3.4028235e+38 + i * 1
sqrt(x) = -806332727296 + i * 1.8446743e+19
==== sqrt<double>() ====
x = -3.4028234663852886e+38 + i * 1
sqrt(x) = 1129.537270565105 + i * 18446743523953729536
==== sqrt<long double>() ====
x = -3.4028234663852886e+38 + i * 1
sqrt(x) = -0.4626957582701517 + i * 18446743523953729536

Confirmed by @lntue.

@cjdb cjdb added bug Indicates an unexpected problem or unintended behavior confirmed Verified by a second party floating-point Floating-point math libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. labels Jan 8, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2025

@llvm/issue-subscribers-bug

Author: Christopher Di Bella (cjdb)

The following program produces an incorrect complex value due to floating-point numbers being unable to store a precise enough angle when converting to polar values.
template&lt;class T&gt;
void sqrt()
{
  auto const x = std::complex&lt;T&gt;{std::numeric_limits&lt;float&gt;::lowest(), 1.0f};
  std::println("x = {} + i * {}", x.real(), x.imag());
  auto const s = std::sqrt(x);
  std::println("sqrt(x) = {} + i * {}", s.real(), s.imag());
}

int main()
{
  std::println("==== expected ====");
  std::println("x = {} + i * {}", std::numeric_limits&lt;float&gt;::lowest(), 1.0f);
  std::println("sqrt(x) = 2.7105055e-20 + i * 1.8446744e19");

  std::println("==== sqrt&lt;float&gt;() ====");
  sqrt&lt;float&gt;();

  std::println("==== sqrt&lt;double&gt;() ====");
  sqrt&lt;double&gt;();
  
  std::println("==== sqrt&lt;long double&gt;() ====");
  sqrt&lt;long double&gt;();
}
==== expected ====
x = -3.4028235e+38 + i * 1
sqrt(x) = 2.7105055e-20 + i * 1.8446744e19
==== sqrt&lt;float&gt;() ====
x = -3.4028235e+38 + i * 1
sqrt(x) = -806332727296 + i * 1.8446743e+19
==== sqrt&lt;double&gt;() ====
x = -3.4028234663852886e+38 + i * 1
sqrt(x) = 1129.537270565105 + i * 18446743523953729536
==== sqrt&lt;long double&gt;() ====
x = -3.4028234663852886e+38 + i * 1
sqrt(x) = -0.4626957582701517 + i * 18446743523953729536

Confirmed by @lntue.

@EugeneZelenko EugeneZelenko removed the bug Indicates an unexpected problem or unintended behavior label Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed Verified by a second party floating-point Floating-point math libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

No branches or pull requests

4 participants