Числовые различия в точности между VS6 и VS2008 при использовании C ++? - PullRequest
1 голос
/ 28 июля 2010

Я работал над переносом унаследованного проекта с Visual Studio 6 на 2008 год. Пройдя несколько препятствий, я теперь строю и выполняю новый проект. Однако я заметил, что выходные данные из двух версий программы очень немного отличаются, как будто вычисления с плавающей запятой не эквивалентны, несмотря на то, что код один и тот же.

Эти различия обычно начинаются довольно небольшими (<1.0E-6), но накапливаются во многих расчетах до того момента, когда они начинают оказывать существенное влияние на выход. В качестве одного примера я рассмотрел точное хранение с двойной точностью в памяти ключевой переменной после одного из первых шагов вычисления и увидел: </p>

Представление Visual Studio 6: 0x4197D6CC85AC68D9
Десятичный эквивалент: 99988257,4183687120676040649414

Представление Visual Studio 2008: 0x4197D6CC85AC68EB
Десятичный эквивалент: +99988257,4183689802885055541992

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

Кто-нибудь знает о каких-либо ожидаемых различиях между арифметическими операциями двойной точности двух версий компилятора? (Или какие-либо другие идеи о том, что может быть причиной этого?)

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

Спасибо!

Ответы [ 2 ]

4 голосов
/ 28 июля 2010

Это только предположение, но большинство современных процессоров Intel / AMD имеют две отдельные модели FPU: старый процессор i386 и более новую модель на базе SSE / SSE2. Последний имеет более гибкую модель программирования и обычно является предпочтительным.

Вы должны проверить, генерируют ли и VS6, и VS2008 код для одной и той же модели, потому что у старой школы FPU есть 80-битные промежуточные результаты, которые могут привести к меньшему округлению и потенциально лучшим результатам, но фактические результаты зависят от оптимизатор делает. Это то, что ученые действительно ненавидят между прочим. Например, если операнды выливаются в память, то они усекаются до 64 бит, и дополнительная точность теряется.

Затем IIRC VS6 не смог сгенерировать код SSE / SSE2, но у него была опция / fp: точная округление всех промежуточных результатов до заявленного размера. Я думаю, что у VS 2008 тоже есть этот флаг. Поэтому я бы посоветовал вам попробовать / fp: точное для обоих компиляторов и снова сравнить результат.

0 голосов
/ 28 июля 2010

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

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

По крайней мере, на x86 большинство операций FP выполняются в 80-битных внутренних регистрах, но имеют только64 бита в памяти.Если промежуточные результаты были скопированы в память (и усечены) в разных точках двумя разными компиляторами, это может привести к разным ответам.Логика оптимизации компилятора, безусловно, может привести к тому, что это будет вести себя по-другому, особенно если новый компилятор использует преимущества дополнительных регистров, которые не использовались старым.

В какой-то момент я знаю, что была опция «использовать согласованную плавающую точку»но я не могу вспомнить, в какой версии он был. Это приводило к тому, что значения усекались до 64 бит после каждой операции, но обеспечивало согласованность результатов при нескольких запусках.

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