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

exp(pi*i) produces slightly incorrect result #392

Open
mgeck64 opened this issue Nov 18, 2021 · 5 comments
Open

exp(pi*i) produces slightly incorrect result #392

mgeck64 opened this issue Nov 18, 2021 · 5 comments

Comments

@mgeck64
Copy link
Contributor

mgeck64 commented Nov 18, 2021

Basically, exp(pi*i) where i is the imaginary unit should produce -1 but produces a slightly different
result with Boost 1.77.0; however it produces the correct result with Boost 1.74.0. The following program reproduces the issue:

#include <boost/multiprecision/cpp_complex.hpp>

using CT = boost::multiprecision::cpp_complex_50;
static const auto pi = boost::math::constants::pi<CT::value_type>();
static const auto i  = CT(0, 1);

int main() {
    std::cout << exp(pi*i) << std::endl;
    // Output when compiled with Boost 1.74.0 is -1 as expected.
    // Output when compiled with Boost 1.77.0 is (-1,4.33483e-51).
    // Note: The equivalent program using std::complex when run in compiler
    // explorer produces a similar result: (-1,1.22465e-16). Don't know if this
    // could be related.
    // Note 2: My version of g++ under which this was compiled is 11.2.0.
}
@NAThompson
Copy link
Contributor

NAThompson commented Nov 18, 2021

Since π is not representable, we must apply the rounding model of floating point arithmetic: π̂=π(1+μ), where μ is the unit roundoff.

Then:

exp(iπ̂) = exp(iπ)exp(iμπ) = -cos(μπ) -isin(μπ) ≈ -1 -iμπ,

which is exactly as you observe.

@mgeck64
Copy link
Contributor Author

mgeck64 commented Nov 18, 2021 via email

@mgeck64
Copy link
Contributor Author

mgeck64 commented Nov 18, 2021

More precisely stated, my question is why sin(pi) correctly evaluates to 0 in version 1.74 but not in 1.77. Note also 1.75 produces the same result as 1.77 so whatever changed happened between 1.74 and 1.75.

Note also that google calculator and wolfram alpha evaluate sin(pi) to 0. In particular, wolfram alpha will evaluate sin(3.1415926535897932384626433832795028841971693993751) to 0.

Is pi being treated specially in 1.74 and the other calculators?

@ckormanyos
Copy link
Member

I made some investigations to give us some content for the discussion.

We are dealing with finite-precision numerical representations and should discuss what makes sense for really small numbers.

#include <boost/multiprecision/cpp_complex.hpp>

using CT = boost::multiprecision::cpp_complex_50;
using component_value_type = typename CT::value_type;
static const auto pi = boost::math::constants::pi<component_value_type>();
static const auto i  = CT(0, 1);

int main()
{
  {
    std::stringstream strm;

    strm << std::setprecision(std::numeric_limits<component_value_type>::digits10)
         << exp(pi*i)
         << std::endl;

    std::cout << strm.str() << std::endl;
  }

  {
    std::stringstream strm;

    strm << std::fixed
         << std::setprecision(std::numeric_limits<component_value_type>::digits10)
         << exp(pi*i)
         << std::endl;

    std::cout << strm.str() << std::endl;
  }

  {
    std::stringstream strm;

    strm << std::fixed
         << exp(pi*i)
         << std::endl;

    std::cout << strm.str() << std::endl;
  }
}

@jzmaddock
Copy link
Collaborator

I believe this is a result of addressing this issue: #264 via: #270

Which means we now do extended precision argument reduction, so reducing an input of PI, no longer results in 0 but something very close to it. I'm in two minds what to do here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants