Числовой код переноса powerpc на intel дает разные результаты при использовании float - PullRequest
6 голосов
/ 28 января 2010

Моя существенная проблема заключается в том, чтобы заставить арифметику с плавающими в 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, но они были достаточно близки, чтобы быть статистически приемлемыми.Учитывая, что обработка выполняется опытным пользователем, выбирающим области интереса, и что пользовательский ввод частично реагирует на ход модели, главный ученый посчитал это приемлемым (это не было ночным решением!).Остальные числовые различия находятся в пределах того, что определяет различные клинические результаты, поэтому при тестировании не было выявлено никаких разных диагнозов.

Ответы [ 3 ]

3 голосов
/ 28 февраля 2010

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

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

1 голос
/ 03 октября 2010

Я рекомендую вам ошибка GCC 323 :

Я хотел бы поприветствовать новых членов сообщества bug 323, где все ошибки с плавающей точкой в ​​x87 в gcc умирают! Все ошибки с плавающей запятой, использующие x87, приветствуются, несмотря на то, что многие из них легко исправимы, а многие нет! Мы все одна счастливая семья, совершаем вопиющую ошибку, стремясь получить точность от самого точного FPU общего назначения на рынке!

Вкратце: невероятно утомительно , чтобы получить "истинные" синглы / двойные числа с плавающей точкой IEEE на x87 без существенного снижения производительности; вы страдаете от двойного округления денорм, даже если вы используете fldcw из-за уменьшенного диапазона показателей (IIRC, IEEE FP специально позволяет реализациям делать свои собственные WRT денормсы). Предположительно, вы могли бы сделать что-то вроде этого:

  1. Округление до положительной бесконечности, выполнение операции (получение ldresult1), округление до ближайшего четного, преобразование в float (получение fresult1).
  2. RTNI, выполнить операцию, RTNE, преобразовать в число с плавающей точкой.
  3. Если они одинаковые, прекрасно: у вас правильный результат RTNE с плавающей запятой. Если нет, то (я думаю) fresult2
  4. ldresult1 == ((long double) fresult1 + fresult2) / 2. «Правильный» ответ: fresult2.
  5. ldresult2 == ((long double) fresult1 + fresult2) / 2. «Правильный» ответ: fresult1.

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

И затем вы столкнулись с другой проблемой: я почти уверен, что нет никакой гарантии, что sqrt () вернет одно и то же разрешение в разных реализациях (и очень уверен в функциях trig); единственная гарантия, которую я когда-либо видел, состоит в том, что результат находится в пределах 1 ульт (предположительно от правильно округленного результата). Он сильно зависит от используемого алгоритма, и современные процессоры имеют инструкции для них, поэтому вы пострадаете от значительного снижения производительности, если попытаетесь реализовать его в программном обеспечении. Тем не менее, ISTR - это «переносимая» библиотека с плавающей точкой, которая должна была обеспечивать согласованность, но я не помню названия OTTOMH.

1 голос
/ 28 января 2010

Не ответ как таковой, но больше текста (и форматирования), чем я мог бы уместить в комментарии. Читая ваш вопрос, мне кажется, что вы, вероятно, рассмотрели все это, но не сказали нам, так что это может быть неуместной болтовней. Если это так, я прошу прощения.

Можете ли вы (не так ли) обеспечить соблюдение правил IEEE754 для арифметики с плавающей запятой в исходной или портированной версиях программы? Мое первое предположение состоит в том, что две платформы (комбинация аппаратного обеспечения, o / s, библиотек) реализуют разные подходы к арифметике fp.

Какие предположения (если таковые имеются) вы сделали относительно размеров по умолчанию на двух платформах некоторых основных типов, таких как целые числа и числа с плавающей запятой. Стандарт C (и я полагаю, стандарт C ++) допускает зависимость от платформы для некоторых таких (не могу вспомнить, какой именно, я действительно программист на Фортране).

Последнее предположение - я привык (в моем мире Фортранни) к указанию констант с плавающей точкой, таких как ваш 4.0, с достаточным количеством цифр для указания всех (десятичных) цифр в предпочтительном представлении, то есть что-то вроде 4.000000000000000000000000. Я знаю, что в Fortran 4-байтовая константа с плавающей запятой, такая как 3.14159625, при автоматическом приведении к 8-байтам не заполняет дополнительные байты дополнительными цифрами в десятичном выражении числа pi. Это может повлиять на вас.

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

Наконец, требуется ли вам, чтобы новая версия давала те же результаты, что и старая, или вы предоставляете своим клиентам уверенность в том, что новая версия дает точные ответы? Ваш вопрос оставляет открытой возможность того, что старая версия программы была «ошибочнее», чем новая, учитывая все источники ошибок в численных вычислениях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...