В C и C ++ вычисления с плавающей запятой по умолчанию не являются детерминированными, поскольку пользователь не выбирает даже истинный тип данных, как для любого промежуточного вычисления подвыражения FP, компилятор может выбрать представление значения с более высокой точностью(то есть как еще один real тип данных) .
[Известно, что некоторые компиляторы (GCC) делали это для любой автоматической переменной, а не только для (анонимного) промежуточного результатаподвыражение.]
Компилятор может сделать это за несколько вычислений, в некоторых функциях;он может делать это в некоторых случаях, а не в других - для одного и того же подвыражения.
Он может даже встроить функцию и использовать разную точность каждый раз, когда функция вызывается в исходном коде. Это означает, что любая встраиваемая функция может иметь зависимый от семантики вызов ;только отдельно скомпилированные, вызываемые ABI функции (те функции, которые вызываются в соответствии с соглашениями, описанными ABI и которые действуют по существу как черный ящик), имеют абсолютную гарантию наличия только одного поведения с плавающей запятой, фиксированного во время отдельного компиляция (это означает, что глобальная оптимизация не происходит).
[Обратите внимание, что это похоже на определение строковых литералов: любые два вычисления одного и того же строкового литерала в исходном коде могут ссылаться на одинаковые или разныесимвольные массивы.]
Это означает, что даже для чисто аппликативных функций фундаментальное равенство f(x) == f(x)
гарантируется, только если используются операции с плавающей запятой (и строковые литералы) , а не (или чтоадрес строкового литерала используется только для доступа к его элементам).
Таким образом, операции с плавающей запятой имеют недетерминированную семантику с произвольным выбором, сделанным компилятором для каждой операции FP (котораякажется намного более извращенцамиТо, что очень небольшая проблема - позволить компилятору выбрать, какое подвыражение A или B будет вычисляться первым в A+B
).
Кажется, что функция, которая выполняет любые вычисления с промежуточными значениями с плавающей запятой, не может использоваться ни в одном STLконтейнер или алгоритм, который ожидает функтор , удовлетворяющий аксиомам , такой, что
- сортирует контейнеры:
set
, map
, multiset
, multimap
- хэшированные контейнеры
- алгоритмы сортировки:
sort
, stable_sort
- алгоритм, работающий в отсортированных диапазонах:
lower_bound
, set_union
, set_intersection
...
, поскольку все двоичные предикаты и хеш-функции должны быть детерминированными, прежде чем аксиомы могут быть даже задуманы , что они должны быть чисто прикладной математической функцией с определенным значением всех возможных входных данных, что никогда не являетсяслучай с недетерминированными промежуточными значениями C ++ с недетерминированными значениями?
Другими словами, являются ли операции с плавающей запятой по умолчанию почти непригодными для использования только на основе стандарта иМожно ли использовать в реальных реализациях, которые имеют некоторые (смутные) неявные гарантии детерминизма?