Вычисление комплексного числа для функции exp / log сильно отличается в MSVC и G ++ - PullRequest
1 голос
/ 05 апреля 2019

Для преобразования некоторых координат в формат GPS я использую комплексные числа (std :: complex).Алгоритм должен быть скомпилирован MSVC (2015) и g ++ (7.3.0).

Я получил большое отклонение в вычислениях для g ++, которое, вероятно, намного больше, чем обычная точность с плавающей запятой, в то время как на MSVC это правильно.Отклонение составляет более 0,04.

Для MSVC не имеет значения, если я беру низкую или высокую точность (/ fp: быстрая или / fp: точная).Для g ++ я попробовал также "-ffloat-store" и отключить SSE (2), но это не помогло.Также пробовал библиотеку MPC (http://www.multiprecision.org/mpc/home.html),, но приводит к тому же результату.

Для g ++ текущие флаги:

-m64 -mfpmath = sse -msse2 -fno-rtti-fopenmp -g -std = gnu ++ 1y

std::complex<double> val = std::complex<double>(-1.8425031517782417e-07, -0.0);
std::complex<double> testExp = std::pow(val, 0.5);
std::cout << "textExp: " << std::setprecision(30) << testExp << std::endl;

На MSVC я получил ожидаемый результат (2.628360765983583e-20, 0.0004292438877582582 ), но на g ++ я получаю фактический(2.628360765983583e-20, -0.0004292438877582582 ).

Таким образом, мнимая часть неверна для gcc.

Любая идея будет оценена.

1 Ответ

2 голосов
/ 08 апреля 2019

На самом деле, если подумать, arg = (-1.8425031517782417e-07, -0.0) ниже разреза, поэтому должен иметь отрицательную мнимую часть. arg = (-1.8425031517782417e-07, 0.0) выше разреза.

/ * g ++ -o so_complex so_complex.cpp ./so_complex * /

#include <complex>
#include <iostream>
#include <iomanip>
#include <limits>

int
main()
{
  const auto w = std::numeric_limits<double>::max_digits10;
  std::cout << std::setprecision(w);

  std::complex<double> val = std::complex<double>(-1.8425031517782417e-07, -0.0);
  std::complex<double> testExp = std::pow(val, 0.5);
  std::cout << '\n';
  std::cout << "arg      : " << val << '\n';
  std::cout << "testExp  : " << testExp << '\n';
  std::cout << "testExp2 : " << testExp * testExp << '\n';
  std::complex<double> testSqrt = std::sqrt(val);
  std::cout << "testSqrt : " << testSqrt << '\n';
  std::cout << "testSqrt2: " << testSqrt * testSqrt << '\n';

  std::cout << '\n';
  std::complex<double> valp = std::conj(val);
  std::complex<double> testExpp = std::pow(valp, 0.5);
  std::cout << "argp     : " << valp << '\n';
  std::cout << "testExp  : " << testExpp << '\n';
  std::cout << "testExp2 : " << testExpp * testExpp << '\n';
  std::complex<double> testSqrtp = std::sqrt(valp);
  std::cout << "testSqrt : " << testSqrtp << '\n';
  std::cout << "testSqrt2: " << testSqrtp * testSqrtp << '\n';
}

Дает:

arg      : (-1.8425031517782417e-07,-0)
testExp  : (2.6283607659835831e-20,-0.00042924388775825818)
testExp2 : (-1.8425031517782414e-07,-2.2564155872441333e-23)
testSqrt : (0,-0.00042924388775825818)
testSqrt2: (-1.8425031517782414e-07,-0)

argp     : (-1.8425031517782417e-07,0)
testExp  : (2.6283607659835831e-20,0.00042924388775825818)
testExp2 : (-1.8425031517782414e-07,2.2564155872441333e-23)
testSqrt : (0,0.00042924388775825818)
testSqrt2: (-1.8425031517782414e-07,0)

Таким образом, MSVC игнорирует нулевой знак. libstdc ++ прав.

...