Моя существенная проблема заключается в том, чтобы заставить арифметику с плавающими в x86 вести себя как PowerPC, переходя от Classic MacOS (CodeWarrior) к Windows (VS 2008).
Код, о котором идет речь,lot, имеет кучу алгоритмов, которые очень итеративны и очень чувствительны в числовом выражении.
Типичная сложная строка:
Ims_sd = sqrt((4.0*Ams*sqr(nz)-8.0*(Ams+Dms)*nz+12.0*sqr(Ams)) /
(4.0*sqr(Ams)*(sqr(nz)-1)) -
sqr(Ims_av))*sqrt(nz-1);
Она написана с использованием typedef'd float
в качествебазовый тип.
Изменение на double
дает очень похожие результаты на обеих платформах, но, к сожалению, цифры неприемлемы, поэтому мы не можем сделать такой простой выход.
Код Mac скомпилированиспользование CodeWarrior и простое отключение генерации инструкций FMADD и FMSUB сильно повлияло на создаваемые числа.Итак, моей отправной точкой был поиск параметров Visual Studio (2008), которые казались наиболее похожими - убедившись, что использовался fused add.Мы подозреваем, что ключ заключается в поведении компилятора при выделении промежуточного хранилища в вычислениях
В настоящее время наилучшие результаты достигаются при комбинации включения SSE2 и /fp:fast
.Включение встроенных функций приводит к дальнейшему отклонению значений от значений Mac.
Документация по переключателю / fp гласит, что только /fp:strict
отключает поведение плавного добавления.
MSDN говорит о связывании FP10.OBJ «перед LIBC.LIB, LIBCMT.LIB или MSVCRT.LIB».чтобы гарантировать 64-битную точность.Очевидно, я достиг этого, указав FP10.OBJ в поле ввода компоновщика (подробный вывод компоновщика показывает его до MSVCRTD.lib).
Я также установил 64-битную точность, вызвав
_controlfp_s(&control_word, _PC_64, MCW_PC);
в DllMain.
Обратите внимание, что проблема в , а не из-за различий вОбработка исключений с плавающей запятой между платформами также не связана с (восхитительным) способом, которым PowerPC допускает деление на ноль целых чисел (просто возвращая ноль), поскольку эти области уже были проверены и адресованы, в огромной степени благодаря PC-Lint .Программа запускается и выдает несколько правдоподобный вывод, но не вполне достаточно.
ОБНОВЛЕНИЕ:
Интересный комментарий от друга: Одна из возможностей заключается в том, что КПП имеет большое количествовременные регистры, которые могут хранить 64-битные промежуточные значения, тогда как код x86 может выгружать и перезагружать FPU (урезание до 4 байтов и потеря точности).
Возможно, именно поэтому SSE2 работает лучше, поскольку (IIRC) имеет больше регистров и больше возможностей для сохранения промежуточных значений.
Одна возможность - ваш код может быть скомпилирован как 64-битный?Режим x64 также имеет больше регистров для промежуточных соединений и лучшие инструкции FP, так что он может быть ближе к PPC по дизайну и исполнению.
Начальное тестирование с 64-битной сборкой фактически приблизилось, как он и предполагал (сначала я подумал, что это не так, но из-за неправильной настройки моделирования).
Окончательное решение
Я уверен, что все, кто интересуется этой темой, достаточно одержимы, они хотели бы знать, как все это сработало в конце.Программное обеспечение закончено и дает согласованные числовые результаты.Нам никогда не удавалось заставить все алгоритмы выдавать идентичные результаты на Mac, но они были достаточно близки, чтобы быть статистически приемлемыми.Учитывая, что обработка выполняется опытным пользователем, выбирающим области интереса, и что пользовательский ввод частично реагирует на ход модели, главный ученый посчитал это приемлемым (это не было ночным решением!).Остальные числовые различия находятся в пределах того, что определяет различные клинические результаты, поэтому при тестировании не было выявлено никаких разных диагнозов.