2010-02-26 2 views
3

Я делаю некоторые численные вычисления, и у меня часто возникали проблемы с вычислениями с плавающей запятой при использовании GCC. Для моей текущей цели я не очень-то сильно интересуюсь реальной точностью результатов, но хочу эту фирменную собственность:Согласованное поведение поплавкового кода с GCC

независимо от того, где тот же код находится в моей программе, когда он запускается на ТОЧНЫХ входах , Я хочу, чтобы он дал ТОЛЬКО результаты.

Как я могу заставить GCC сделать это? И конкретно, каково поведение - fast-math и разных -О оптимизации?

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

Опять же, я хочу:

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

может ли кто-нибудь сказать мне, как можно решить эту проблему?

ответ

-1

Я думаю, что GCC довольно хорошо документирован, поэтому я не собираюсь раскрывать свое невежество, пытаясь ответить на части вашего вопроса о его вариантах и ​​их эффектах. Однако я бы сделал общее утверждение о том, что при использовании числовой точности и производительности он платит большие дивиденды за чтение руководства.Умные люди, которые работают в GCC, приложили немало усилий в свою документацию, считая, что это полезно (хорошо, это может быть пустяком, но, черт возьми, это руководство для компилятора, а не лифчик).

Если для вас важно, чтобы вы получали точные результаты с идентичными по последнему биту, вам придется беспокоиться не только о GCC, но и о том, как вы можете контролировать его поведение. Вам нужно будет заблокировать библиотеки, которые он вызывает, оборудование, на котором он работает, и, возможно, ряд других факторов, о которых я еще не думал. В худшем (?) Случае, который вы, возможно, захотите, и я это сделал, напишите свои собственные реализации математики f-p, чтобы гарантировать бит-идентичность между платформами. Это сложно и, следовательно, дорого, и вы, возможно, менее уверены в правильности вашего собственного кода, чем код usd от GCC.

Однако, вы пишете

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

, который наталкивает на вопрос для вас - почему бы вам просто не использовать пятизначную цифру в качестве вашего стандарта (уменьшенной) точности? Это то, что очень многие из нас в численных вычислениях делают все время; мы игнорируем более тонкие аспекты численного анализа, поскольку они сложны и дорогостоящи во время вычислений, чтобы обойти. Я думаю о вещах, таких как интервальная арифметика и математика с высокой точностью. (Конечно, если 5 не подходит для вас, выберите другой однозначный номер.)

Но хорошая новость в том, что это вполне оправдано: мы имеем дело с научными данными, которые по своей природе поставляются с (конечно, мы, как правило, не знаем, что такое ошибки, но это другое дело), ​​поэтому вполне нормально игнорировать последние несколько цифр в десятичном представлении, скажем, 64-битного числа fp. Идите прямо и проигнорируйте еще несколько из них. Еще лучше, неважно, сколько битов у ваших чисел f-p, вы всегда будете терять некоторую точность, делая численные вычисления на компьютерах; добавление большего количества бит просто подталкивает ошибки назад, как к наименьшим значащим битам, так и к концу длительных вычислений.

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

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

1

Если ваши цели включают в себя процессоры x86, использование коммутатора, который делает gcc, используя инструкции SSE2 (вместо исторических стековых), сделает их более похожими на другие.

Если ваши цели включают в себя процессоры PowerPC, с помощью переключателя, что делает GCC не использовать fmadd инструкции (заменить умножение с последующим добавлением в исходном коде) будет делать это работать более, как другие.

Не использовать --fast-math: это позволяет компилятору принимать некоторые ярлыки, что может вызвать различия между архитектурами. Gcc является более стандартным и, следовательно, предсказуемым, без этой опции.

Включая свои собственные математические функции (exp, sin, ...) в ваше приложение вместо того, чтобы полагаться на те из библиотеки системы, может только помочь с предсказуемостью.

И наконец, даже если компилятор строго соблюдает стандарт (я имею в виду здесь C99), могут быть некоторые различия, поскольку C99 позволяет вычислять промежуточные результаты с более высокой точностью, чем требуется по типу выражения. Если вы действительно хотите, чтобы программа всегда давала те же результаты, напишите three-address code. Или используйте только максимальную точность, доступную для всех вычислений, которая была бы double, если вы можете избежать исторических команд x86. В любом случае do не использует поплавки с более низкой точностью, чтобы повысить предсказуемость: эффект был бы противоположным, как указано выше в стандарте.

+0

Кроме того, то, что вас беспокоит, - это именно то, что беспокоит людей, которые пытаются написать правильные анализаторы для C, поэтому вы должны быть заинтересованы в этом отчете: http://hal.archives-ouvertes.fr/hal- 00128124/ru /. За исключением того, что авторы анализаторов не имеют контроля над параметрами компиляции, но они работают в рамках, где этого достаточно, чтобы учесть все возможности, не забывая о них. –

Смежные вопросы