Хотя в математике сложение и умножение действительных чисел являются ассоциативными операциями, эти операции не ассоциативны при выполнении над типами с плавающей запятой, такими как float
, из-за ограниченной точности и расширения диапазона.
Так что порядок имеет значение.
Учитывая примеры, число 10000000003.14 не может быть точно представлено как 32-битное float
, поэтому результат (3.14f + 1e10f)
будет равен 1e10f
, ближайшему представимому числу. Конечно, вместо 3.14f + (1e10f - 1e10f)
получится 3.14f
.
Обратите внимание, что я использовал постфикс f
, потому что в C выражение (3.14+1e10)-1e10
включает double
литералов, так что результатом будет действительно 3.14
(или, что более вероятно, что-то вроде 3.14999).
Нечто подобное происходит и во втором примере, где 1e20f * 1e20f
уже находится за пределами диапазона float
(но не double
) и последовательное умножение бессмысленно, а (1e20f * 1e-20f)
, выполняемое первым в другом выражении, имеет вполне определенный результат (1) и последовательное умножение дает правильный ответ.
На практике есть некоторые меры предосторожности, которые вы принимаете
- Используйте более широкий шрифт.
double
лучше всего подходит для большинства приложений, если нет других требований.
- Измените порядок операций, если это возможно. Например, если вам нужно добавить много терминов и вы знаете, что некоторые из них меньше других, начните добавлять их, а затем остальные. Избегайте вычитания чисел одного порядка. В общем, может существовать более точный способ вычисления алгебраического выражения, чем наивный (например, метод Хорнера для полиномиального вычисления).
- Если у вас есть какие-то знания о проблемной области, вы, возможно, уже знаете, какая часть вычислений может иметь проблемные значения, и проверьте, больше (или меньше) ли они, чем некоторые пределы, прежде чем выполнять вычисление.
- Проверьте результаты как можно скорее. Нет смысла продолжать вычисление, когда у вас уже есть бесконечное значение или NaN, или продолжать итерацию, когда целевое значение вообще не изменяется.
person
Bob__
schedule
10.10.2020