Почему виртуальная машина Windows выдает результаты с плавающей запятой, отличные от Linux? - PullRequest
0 голосов
/ 26 сентября 2018

Проблема

У нас есть несколько машин с Ubuntu с очень похожими характеристиками.Мы запустили простую программу для проверки проблемы, которую мы видим в виртуальной машине Windows, на которой работает каждая из этих машин.Скомпилировано с использованием gcc 4.8.4 на 64-битной машине Linux и v140 в Visual Studio на 64-битной виртуальной машине Windows.

#include <cmath>
#include <stdio.h>

int main()
{
  double num = 1.56497856262158219209;
  double numHalf = num / 2.0;

  double cosVal = cos(num);
  double cosValHalf = cos(numHalf);

  printf("num = %a\n", num);
  printf("numHalf = %af\n", numHalf);
  printf("cosVal(num) = %a\n", cosVal);
  printf("cosValHalf(numHalf) = %a\n", cosValHalf);

  //system("pause");
  return 0;
}

Проблема возникает при запуске одного и того же двоичного файла на хост-машинах с определенными ЦП..

Результаты

В Linux все машины выдают одинаковый результат.На виртуальной машине Windows выдаются разные результаты, даже если версии и настройки виртуальной машины одинаковы.Кроме того, двоичные файлы, генерируемые на каждой виртуальной машине, будут давать разные результаты при перемещении на другой хост-компьютер;т.е. двоичный файл, сгенерированный в VM2, но выполненный на LM1, возвратил те же результаты, как если бы VM1 сгенерировал двоичный файл.Мы даже скопировали виртуальную машину, чтобы подтвердить это поведение и, конечно же, оно продолжается.

С усилиями, описанными выше, я думаю, что это не различие библиотеки или проблема виртуальной машины.Что касается выходных данных, следующие процессоры выдают эти результаты:

  • Процессор Intel® Xeon® E5-2630 0
  • Процессор Intel® Xeon® E5-2630 v2

Прежние процессоры дают одинаковые результаты для Linux и Windows.Результаты представлены в шестнадцатеричном виде, потому что читаемость имеет значение меньше, чем при наличии расхождений.

num = 0x1.90a26f616699cp+0
numHalf = 0x1.90a26f616699cp-1
cosVal(num) = 0x1.7d4555e817bdcp-8
cosValHalf(numHalf) = 0x1.6b171bb5e3434p-1

Эти процессоры дают результаты на виртуальной машине Windows, отличные от их аналога Linux:

  • Intel® Xeon (R) CPU E5-2630 v3
  • Intel® Xeon (R) CPU E3-1270 v5

Я не уверен, как эти результаты достигаются.Разборка на VS2015 показывает, что обе программы генерируют одинаковые инструкции независимо от того, на каком хост-компьютере он был скомпилирован.

num = 0x1.90a26f616699cp+0
numHalf = 0x1.90a26f616699cp-1
cosVal(num) = 0x1.7d4555e817bdcp-8
cosValHalf(numHalf) = 0x1.6b171bb5e3435p-1

Вопрос

Почему Windows на виртуальной машине по-разному обрабатывает двоичный файл при установкена машине с конкретным процессором?

Если посмотреть на различия между процессорами E5-2630 v2 и E5-2630 v3, например , то процессоры дают разные результаты поддерживают инструкции AVX2, F16C и FMA3 Устанавливает, где в качестве прежних процессоров нет.Однако, если бы это и стало причиной расхождений, я бы также подумал, что результаты останутся одинаковыми для Linux и Windows.Кроме того, разборка показала, что используемые регистры были одинаковыми на любом чипе.После отладки файла и пошагового выполнения каждой инструкции вы можете подумать, что поведение будет аналогичным.

Все это подводит итог, вероятно, это различие в архитектуре.Любые мысли о том, как я могу быть уверен?

Ресурсы

Я нашел следующие вопросы несколько полезными в отношении решений продвижения cross-платформа согласованности и получение результатов более детерминированность .Я также долго гулял по сравнению с плавающей точкой и не могу порекомендовать его всем, кто интересуется этой темой.

...