Неправильная двойная инициализация в Windows / MSYS2 по сравнению с Linux

Эта простая программа дает неверный результат в Windows / MSYS2. В Ubuntu 18.04 он работает правильно:

#include <math.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
  double a = -1.5708;
  double c = cos(-1.5708);
  double d = cos(a);
  unsigned long long *lc = (unsigned long long *)&c;
  unsigned long long *ld = (unsigned long long *)&d;
  printf("c = %.17e %llu\n", c, *lc);
  printf("d = %.17e %llu\n", d, *ld);
  if (c == d)
    printf("correct result\n");
  else
    printf("wrong result\n");
  return 0;
}

Windows / MSYS2:

$ gcc cos.c -o cos -lm ; ./cos
c = -3.67320510334657393e-06 13749155573439758092
d = -3.67320510334657563e-06 13749155573439758096
wrong result

Ubuntu 18.04:

olivier@ubuntu:~$ gcc cos.c -o cos -lm ; ./cos
c = -3.67320510334657393e-06 13749155573439758092
d = -3.67320510334657393e-06 13749155573439758092
correct result

Я что-то делаю не так, это ошибка gcc на MSYS2 или что-то еще?

# gcc msys2
Источник
  • 0
    Подтверждено на Win7 с MinGW с использованием gcc -msse2 -mfpmath=sse ... обеспечивает правильный вывод.
  • 0
    Использование gcc cos.c -msse2 -mfpmath=sse -o cos -lm действительно работало для меня на MSYS2 с 64-битным gcc.
Codelisting
за 1 против
Лучший ответ

Нельзя ожидать получения побитовых идентичных результатов для функций с плавающей запятой, кромеsqrt через системы.

Более конкретноcos не гарантируется правильное округление, поэтому результат библиотеки времени выполнения (ваш второй результатd ) не обязательно идентичен результату сворачивания констант, происходящего во время компиляции (ваш результатc ).

Например, на странице GCC FP Math указано, что во время сворачивания констант все операции правильно округляются (даже трансцендентные функции), но обычно это не относится к библиотеке времени выполнения из соображений эффективности. (Также не все компиляторы предоставят вам эту правильно округленную гарантию для сворачивания констант, поэтому для кросс-компиляторов или компиляторов, которые используют libm, отличную от сгенерированного исполняемого файла, вы можете столкнуться с этой проблемой.)

GCC внутренне использует библиотеку MPFR, которая реализует правильно округленные операции с промежуточной арифметикой произвольной точности, но в библиотеке времени выполнения это было бы слишком медленно.

Даже для linux вы, вероятно, найдетеcos функция так, чтобы возникли разногласия между вашимиc а такжеd (если они не используют crlibm под капотом). Так что идентичныc а такжеd результаты для linux, по моему мнению, совпадают.

Если вы ищете более предсказуемые математические результаты FP во время выполнения, вы можете проверить crlibm , которая является эффективной реализацией многих функций с плавающей запятой, которые дают правильно округленные результаты. Он намного эффективнее MPFR, но не так эффективен, как стандартные функции libm.

Codelisting
Популярные категории
На заметку программисту