Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
GBP
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
64-битные программы и вычисления с плав…

64-битные программы и вычисления с плавающей точкой

18 Авг 2010

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

Текст письма

Хочу задать вам один конкретный вопрос, касающийся миграции 32 -> 64 бита. Статьи и материалы на вашем сайте я изучал, тем более был удивлён тому несоответствию в работе 32- и 64-битного кода, что я обнаружил.

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

float fConst = 1.4318620f; 
float fValue1 = 40.598053f * (1.f - 1.4318620f / 100.f); 
float fValue2 = 40.598053f * (1.f - fConst / 100.f);

MSVC 32, SSE и SSE2 отключены

/fp:precise: fValue1 = 40.016743, fValue2 = 40.016747

MSVC 64, SSE и SSE2 отключены

/fp:precise: fValue1 = 40.016743, fValue2 = 40.016743

Проблема в том, что отличаются значения fValue2. Из-за этого несоответствия код, скомпилированный под 32 и под 64 бита, даёт разные результаты, что недопустимо в моём случае (да и, наверное, недопустимо вообще).

Находит ли что-то похожее ваш продукт? Не могли бы вы дать наводку, как 32/64 может влиять на то, что выдаёт вещественная арифметика?

Наш ответ

Продукт Viva64 не выявляет подобные изменения в поведении в программы после ее перекомпиляции для 64-битной системы. Подобные изменения нельзя назвать ошибочными. Давайте разберемся с описанной ситуацией подробней.

Простое объяснение

Взглянем для начала на то, что выдает 32-битный компилятор: fValue1 = 40.016743, fValue2 = 40.016747.

Вспомним, что тип float имеет 7 значащих цифр. Отсюда видно, что на самом деле мы получаем значение, которое чуть больше 40.01674 (семь значащих цифр). Будет ли это на самом деле 40.016743 или 40.016747 не имеет значения, поскольку это за пределами точности типа float.

При компиляции в 64-битном режиме компилятор генерирует такой же корректный код, в результате которого мы получаем то же самое значение "чуть больше 40.01674". В данном случае это всегда 40.016743. Но это не имеет значения. В рамках точности типа float мы получаем такой же результат, как и в 32-битной программе.

Еще раз - результат вычислений на 32-битной и 64-битной системе одинаков в рамках возможностей типа float.

Более строгое объяснение

Точностью типа float является значение FLT_EPSILON, равное 0.0000001192092896.

Если мы прибавим к 1.0f значение меньше чем FLT_EPSILON, то получим вновь 1.0f. Только прибавление к 1.0f значения равного или большего FLT_EPSILON увеличит значение переменной: 1.0f + FLT_EPSILON !=1.0f.

В нашем случае мы работаем не с единицей, а со значениями 40.016743, 40.016747. Возьмем максимальное из них и умножим на FLT_EPSILON. Полученное число будет значением точности для наших вычислений:

Epsilon = 40.016743*FLT_EPSILON = 40.016743*0.0000001192092896 = 0,0000047703675051357728

Посмотрим, насколько различаются числа 40.016747 и 40.016743:

Delta = 40.016747 - 40.016743 = 0.000004

Оказывается, что разница меньше, чем погрешность:

Delta < Epsilon

0.000004 < 0,00000477

Следовательно, 40.016743 == 40.016747 в рамках типа float.

Как поступить?

Хотя все корректно, от этого, к сожалению часто не легче. Если есть желание сделать систему более детерминированной, то можно использовать ключ /fp:strict.

В этом случае результат работы будет следующий:

MSVC x86:

/fp:strict: fValue1 = 40.016747, fValue2 = 40.016747

MSVC x86-64:

/fp:strict: fValue1 = 40.016743, fValue2 = 40.016743

Результат стал более стабильный, но мы опять не достигли идентичного поведения 32-битного и 64-битного кода. Что делать? Только смириться и изменить методику сравнения результатов.

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

Я занимался разработкой пакета численного моделирования. Была поставлена задача, разработать систему регрессионных тестов. Есть набор проектов, результат которых просмотрен физиками и оценен как корректный. Правки кода, вносимые в проект не должны приводить к тому, чтобы выходные данные начали отличаться. Если в какой-то точке в момент t давление 5 атмосфер, то это давление должно остаться в ней и после добавления новой кнопки в диалоге или оптимизации механизма начального заполнения области. Если что-то меняется, то значит, были правки в модели и физики должны заново оценить все изменения. Естественно предполагается, что подобные правки модели крайне редкая ситуация. В нормальном режиме разработки проекта должны получаться идентичные данные. Однако это теоретически. На практике все сложнее. Идентичный результат не всегда можно было получить, работая даже с одним компилятором с одинаковыми ключами оптимизации. Результаты все равно очень легко начинали "плыть". Но поскольку проект еще и собирался различными компиляторами под различные платформы, то получить совершенно идентичные значения было признано не решаемой задачей. Вернее возможно задача и решаемая, но это требует огромное количество усилий и приведет к недопустимому падению скорости вычислений из-за невозможности оптимизаций кода. Решением стала специальная система сравнения результатов. Причем значения в различных точках сравнивались не просто с точностью Epsilon, а специальным образом. Подробности реализации я уже не помню, но идея была следующая. Если в области протекают процессы, в результате которой максимум давления составляет 10 атмосфер, то в другой точке, разница в 0.001 атмосферу считается ошибкой. Однако если протекает процесс, где образуются участки с давлением 1000 атмосфер, то разница в 0.001 уже считается допустимой погрешностью. Таким образом, удалось построить достаточно надежную систему регрессионного тестирования, которая, думается, с успехом работает и поныне.

Последний момент, а почему все-таки мы получаем разный результат в 32-битном и 64-битном коде?

Видимо дело в том, что используется разный набор инструкций. В 64-битном режиме теперь всегда используются SSE2 инструкции, которые реализованы во всех процессорах семейства AMD64 (Intel 64). Кстати, поэтому в исходном вопросе фраза "MSVC 64, SSE и SSE2 отключены" является неверной. SSE2 используется 64-битным компилятором в любом случае.

Дополнительные ресурсы

Популярные статьи по теме
PVS-Studio ROI

Дата: 30 Янв 2019

Автор: Андрей Карпов

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

Дата: 21 Ноя 2018

Автор: Андрей Карпов

Краткое описание технологий, используемых в инструменте PVS-Studio, которые позволяют эффективно обнаруживать большое количество паттернов ошибок и потенциальных уязвимостей. Статья описывает реализа…
Любите статический анализ кода!

Дата: 16 Окт 2017

Автор: Андрей Карпов

Я в шоке от возможностей статического анализа кода, хотя сам участвую в разработке инструмента PVS-Studio. На днях я был искренне удивлён тому, что анализатор оказался умнее и внимательнее меня.
Как PVS-Studio оказался внимательнее, чем три с половиной программиста

Дата: 22 Окт 2018

Автор: Андрей Карпов

PVS-Studio, как и другие статические анализаторы кода, часто выдаёт ложные срабатывания. Но не стоит спешить считать странные срабатывания ложными. Это короткая история о том, как PVS-Studio вновь ок…
Эффект последней строки

Дата: 31 Май 2014

Автор: Андрей Карпов

Я изучил множество ошибок, возникающих в результате копирования кода. И утверждаю, что чаще всего ошибки допускают в последнем фрагменте однотипного кода. Ранее я не встречал в книгах описания этого …
Зло живёт в функциях сравнения

Дата: 19 Май 2017

Автор: Андрей Карпов

Возможно, читатели помнят мою статью под названием "Эффект последней строки". В ней идёт речь о замеченной мной закономерности: ошибка чаще всего допускается в последней строке однотипных блоков текс…
Бесплатный PVS-Studio для тех, кто развивает открытые проекты

Дата: 22 Дек 2018

Автор: Андрей Карпов

В канун празднования нового 2019 года команда PVS-Studio решила сделать приятный подарок всем контрибьюторам open-source проектов, хостящихся на GitHub, GitLab или Bitbucket. Им предоставляется возмо…
Как и почему статические анализаторы борются с ложными срабатываниями

Дата: 20 Мар 2017

Автор: Андрей Карпов

В своей предыдущей статье я писал, что мне не нравится подход, при котором статические анализаторы кода оцениваются с помощью синтетических тестов. В статье приводился пример, воспринимаемый анализат…
PVS-Studio для Java

Дата: 17 Янв 2019

Автор: Андрей Карпов

В седьмой версии статического анализатора PVS-Studio мы добавили поддержку языка Java. Пришло время немного рассказать, как мы начинали делать поддержку языка Java, что у нас получилось и какие дальн…
Главный вопрос программирования, рефакторинга и всего такого

Дата: 14 Апр 2016

Автор: Андрей Карпов

Вы угадали, ответ - "42". Здесь приводится 42 рекомендации по программированию, которые помогут избежать множества ошибок, сэкономить время и нервы. Автором рекомендаций выступает Андрей Карпов - тех…

Комментарии (0)

Следующие комментарии

На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять