5

Я разрабатываю приложение C, которое требует детерминизма с плавающей запятой. Мне также хотелось бы, чтобы операции с плавающей запятой были достаточно быстрыми. Сюда входят стандартные трансцендентные функции, не указанные IEEE754 как синус и логарифм. Программные реализации с плавающей запятой, которые я рассматривал, относительно медленны, по сравнению с аппаратной плавающей точкой, поэтому я рассматриваю возможность простого округления одного или двух наименее значимых битов от каждого ответа. Потеря точности является адекватным компромиссом для моего приложения, но этого достаточно для обеспечения детерминированных результатов на разных платформах? Все значения с плавающей запятой будут удваиваться.Могу ли я использовать округление для обеспечения детерминизма операций с атомами с плавающей запятой?

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

Было бы замечательно, если бы сегодня использовались программные реализации основных аппаратных реализаций с плавающей запятой, поэтому я мог бы непосредственно проверить эту гипотезу.

+4

Большинство компиляторов сегодня имеют какой-то вариант строгого FP. Это, вероятно, делает то, что вы хотите. – Mysticial

+0

У IEE-754 уже есть правила округления, поэтому маловероятно, что какие-либо правила, которые вы применяете поверх него, улучшат ситуацию. Можете ли вы уточнить, что вы подразумеваете под «детерминированными результатами»? –

+0

@Mark Тот же код даст разные результаты для разных аппаратных средств для кода с плавающей точкой. Я предполагаю, что именно здесь подразумевается * детерминированный *. –

ответ

2

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

Во-первых, поймите: это не будет переносимым для всех машин. Например. Ядро с плавающей точкой мейнфрейма IBM не является IEEE и не дает одинаковых ответов. Чтобы получить это точно, вам понадобится программная реализация стандартных операций IEEEE, таких как добавление и умножение FP.

Я предполагаю, что вы заботитесь только о машинах, которые реализуют стандартную плавающую точку IEEE. И я также предполагаю, что вы не беспокоитесь о NaNs, поскольку NaNs не были полностью стандартизованы IEEE 754-1985, и возникли две противоположные реализации: HP и MIPS, vedrsus почти все остальные. 1

С этими ограничениями, как вы можете получить изменчивость в своих расчетах?

(1) Если код распараллелен. Убедитесь, что этого не происходит. (Это маловероятно, но некоторые машины могут.) Параллелизация является основным источником изменения результатов в FP. По крайней мере, одна компания, которую я знаю, кто заботится о воспроизводимости и параллелизме, отказывается использовать FP и использует только целое число.

(2) Убедитесь, что устройство настроено соответствующим образом.

E.g. большинство компьютеров вычисляют в 32 или 64-битной точности (исходный стандарт C был 64-битным «двойным» везде. Но Intel x86/x87 может вычислять в 80 бит в регистре и округлять до 64 или 32 при разливе. 1 показывает, как изменить x86/x87 с 80 бит до 64 бит, используя встроенную сборку. Обратите внимание, что этот код является уровнем сборки, а не переносимым, но большинство других машин уже выполняют вычисления с точностью 32 или 64 бит, и вам не нужно беспокоиться о том, x87 80 бит.

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

E.g. убедитесь, что вы используете один и тот же режим underflow на всех машинах. То есть обеспечить денормацию или включить или наоборот, чтобы все машины находились в режиме «с нуля до нуля». Вот выбор Добсона: режимы «с нуля до нуля» не стандартизированы, но некоторые машины, например. Графические процессоры просто не имели денормализованных номеров. То естьна многих машинах есть стандартный номер стандарта IEEE FORMATS, но не фактическая стандартная арифметика IEEE (с деньгами). Мой druther должен требовать IEEE denorms, но если бы я был абсолютно параноиком, я бы пошел с нуля до нуля и запустил бы себя в программном обеспечении.

(3) Убедитесь, что вы используете один и тот же язык ioptions. Программы Older C выполняют все вычисления в «двойном» (64-разрядном), но теперь можно рассчитывать с одной точностью. Как бы то ни было, вы хотите сделать это одинаково на всех машинах.

(4) Некоторые мелкие детали WRT кода:

Избегайте большие выражения, которые компилятор может изменить (если он не выполняет строгие FP переключателей правильно)

Возможной запись всего кода в простой форме, как

double a = ...; 
double b = ...; 
double c = a *b; 
double d = ...; 
double e = a*d; 
double f = c + e; 

Вместо того

f = (a*b) + (a*c); 

, которые могут быть оптимизированы для

f = a*(b+c); 

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

Если вы все это делаете, ваши расчеты должны быть абсолютно повторяемыми. Плавающая точка IEEE является точной - она ​​всегда дает те же ответы. Это перестройка вычислений компилятором на пути к IEEE FP, который вводит изменчивость.

Не должно быть необходимости округлять бит младшего порядка. Но делать это также не повредит, и может замаскировать некоторые проблемы. Помните: вам может понадобиться замаскировать хотя бы один бит для каждого добавления ....

(2) Оптимизация компилятора, изменяющая код по-разному на разных машинах. Как сказал один из комментаторов, используйте все, что бы переключили ваш компилятор для строгих FP.

Возможно, вам придется отключить всю оптимизацию для файла, содержащего ваш код sin.

Возможно, вам придется использовать летучие вещества.

Надеемся, что есть более специфичные переключатели компилятора. Например. для gcc:

-ffp-contract = off --- disable fused multiply add, так как не все ваши целевые машины могут иметь их.

-fexcess точности = стандартный --- отключает такие вещи, как Intel x86/x87 избыточном точности во внутренних регистрах

-std = c99 --- определяет довольно строгий стандарт языка C. К сожалению, не полностью реализован, как я Google сегодня

убедитесь, что вы не оптимизаций включены как -funsafe-математических и -fassociativbe-математических

+0

Не могу поверить, что я написал все вышеизложенное и забыл упомянуть: Супераккумуляторы - это действительно классный способ предоставления бит-точных вычислений с плавающей запятой. Я цитирую «fp», потому что супераккумуляторы на самом деле не являются плавающей точкой - они действительно представляют собой БОЛЬШИЕ значения целочисленной фиксированной точки. Я упоминаю их в http://semipublic.comp-arch.net/wiki/Superaccumulator, указав на некоторые классические статьи. –

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