Современные процессоры, которые реализуют 64-разрядные числа с плавающей запятой, обычно реализуют нечто, близкое к стандарту IEEE 754-1985, недавно замененное стандартом 754-2008.
Стандарт 754 определяет, какой результат вы должны получить от определенных базовых операций, особенно сложения, вычитания, умножения, деления, квадратного корня и отрицания. В большинстве случаев числовой результат указывается точно: результатом должно быть представимое число, наиболее близкое к точному математическому результату в направлении, заданном режимом округления (до ближайшего, к бесконечности, к нулю или к отрицательной бесконечности). В режиме «до ближайшего» стандарт также определяет, как нарушаются связи.
Из-за этого операции, не связанные с условиями исключения, такими как переполнение, будут получать одинаковые результаты на разных процессорах, соответствующих стандарту.
Однако есть несколько проблем, которые мешают получать одинаковые результаты на разных процессорах. Одним из них является то, что компилятор часто может реализовывать последовательности операций с плавающей запятой различными способами. Например, если вы напишите «a = b c + d» на C, где все переменные объявлены как double, компилятор может свободно вычислять «b c» в арифметике с двойной точностью или чем-то еще диапазон или точность. Если, например, процессор имеет регистры, способные хранить числа с плавающей точкой с расширенной точностью, и выполнение арифметики с расширенной точностью не займет больше времени процессора, чем выполнение арифметики с двойной точностью, компилятор, скорее всего, сгенерирует код с использованием расширенной -precision. На таком процессоре вы можете не получить такие же результаты, как на другом процессоре. Даже если компилятор делает это регулярно, это может не произойти в некоторых обстоятельствах, потому что регистры переполнены во время сложной последовательности, поэтому он временно сохраняет промежуточные результаты в памяти. Когда он это делает, он может записать только 64-битное двойное число, а не число с расширенной точностью. Таким образом, подпрограмма, содержащая арифметику с плавающей точкой, может давать разные результаты только потому, что она скомпилирована с другим кодом, возможно, встроенным в одном месте, и компилятору нужны регистры для чего-то еще.
Некоторые процессоры имеют инструкции для вычисления умножения и сложения в одной инструкции, поэтому «b c + d» может быть вычислено без промежуточного округления и получить более точный результат, чем на процессоре, который сначала вычисляет b с, а затем добавляет д.
Ваш компилятор может иметь переключатели для управления поведением, подобным этому.
В некоторых местах стандарт 754-1985 не требует уникального результата. Например, при определении того, произошел ли недостаток (результат слишком мал, чтобы его можно было точно представить), стандарт позволяет реализации выполнить определение либо до, либо после того, как он округляет значение и (биты дроби) до целевой точности. Таким образом, некоторые реализации скажут вам, что недопоставка произошла, когда другие реализации не будут.
Общей особенностью процессоров является наличие режима «почти IEEE 754», который устраняет сложность борьбы с недостаточным расходом, заменяя ноль вместо того, чтобы возвращать очень маленькое число, требуемое стандартом. Естественно, вы получите другие числа при выполнении в таком режиме, чем при выполнении в более совместимом режиме. По соображениям производительности несовместимый режим может быть установлен по умолчанию вашим компилятором и / или операционной системой.
Обратите внимание, что реализация IEEE 754 обычно предоставляется не только аппаратным обеспечением, но и сочетанием аппаратного и программного обеспечения. Процессор может выполнять большую часть работы, но полагаться на программное обеспечение для обработки определенных исключений, установки определенных режимов и т. Д.
Когда вы переходите от базовых арифметических операций к таким вещам, как синус и косинус, вы очень зависите от используемой вами библиотеки. Трансцендентные функции обычно рассчитываются с помощью тщательно спроектированных приближений. Реализации разрабатываются разными инженерами независимо друг от друга и получают разные результаты. В одной системе функция sin может давать точные результаты в ULP (единица наименьшей точности) для небольших аргументов (меньше чем pi) или более, но для больших аргументов ошибки больше. В другой системе функция sin может выдавать результаты с точностью до нескольких ULP для всех аргументов. Не известно ни одной текущей математической библиотеки, которая бы вырабатывала правильно округленные результаты для всех входных данных. Существует проект crlibm (правильно закругленный Libm), который проделал хорошую работу для достижения этой цели, и они разработали реализации для значительных частей математической библиотеки, которые правильно округлены и имеют хорошую производительность, но не для всей математической библиотеки. еще.
Таким образом, если у вас есть управляемый набор вычислений, вы понимаете реализацию своего компилятора и очень осторожны, вы можете полагаться на идентичные результаты на разных процессорах. В противном случае получение абсолютно идентичных результатов - это не то, на что вы можете положиться.