Неопределенность типа данных с плавающей точкой
Я делаю численный анализ математического программного обеспечения, которое я разработал. Я хочу определить, в чем заключается неопределенность моего результата. бытие f()
мой метод и x
входное значение, я хочу идентифицировать y
моего результата как f(x) +/- y
, мой f()
Метод имеет несколько операций между float
переменные. Чтобы изучить распространение ошибки произошло в f()
Я должен применить формулы статистического распространения неопределенности, и для этого я должен знать неопределенность float
переменная.
Я понимаю архитектуру float
переменная, как указано в стандарте IEEE 754, и ошибка округления, преобразующая десятичное значение в float
присущ последнему.
Из того, что я понял из литературы, FLT_EPSILON
макрос в http://www.cplusplus.com/reference/cfloat/ определяет мой y
значение, но этот быстрый тест доказывает, что это неправильно:
float f1 = 1.234567f;
float f2 = 1.234567f + 1.192092896e-7f;
float f3 = 1.234567f + 1.192092895e-7f;
printf("Inicial:\t%f\n", f1);
printf("Inicial:\t%f\n", f2);
printf("Inicial:\t%f\n\n", f3);
Выход:
Inicial: 1.234567
Inicial: 1.234567
Inicial: 1.234567
Когда ожидаемый результат должен быть:
Inicial: 1.234567
Inicial: 1.234568 <---
Inicial: 1.234567
В чем я не прав? Не должен float
ценность x + FLT_EPSILON
а также x - FLT_EPSILON
быть таким же?
РЕДАКТИРОВАТЬ: мой вопрос R
float
ценность x
, что y
ценить это x + y || x - y
равняется тому же R
float
значение?
3 ответа
Распространение неопределенности происходит из области статистики и относится к тому, как неопределенности в исходных данных влияют на их математические функции. Анализ ошибок, возникающих в вычислительной арифметике, является численным анализом.
FLT_EPSILON
не является мерой неопределенности или ошибки в результатах с плавающей точкой. Это расстояние между 1 и следующим значением, представляемым в float
тип. Следовательно, это размер шагов между представимыми числами на величину 1.
Когда вы преобразуете десятичное число в число с плавающей запятой, полученная ошибка округления может иметь величину до 1/2 размера шага при использовании общего режима округления до ближайшего. Причина, по которой граница равна ½ размера шага, заключается в том, что для любого числа x (в пределах конечной области формата с плавающей запятой) существует представимое значение в пределах ½ размера шага (включительно). Это связано с тем, что если представимое число больше 1/2 размера шага в одном направлении, то представимое число меньше 1/2 размера шага в другом направлении.
Размер шага зависит от величины чисел. С двоичной переменной с плавающей точкой она удваивается в 2, и снова в 4, затем в 8 и так далее. Ниже 1 он делится пополам, и снова на ½, ¼ и так далее.
Когда вы выполняете арифметические операции с плавающей запятой, округление, которое происходит в вычислении, может составлять или отменять предыдущие ошибки. Нет общей формулы для окончательной ошибки.
Две цифры, используемые в вашем примере кода, 1.192092897e-7f
а также 1.192092896e-7f
, настолько близко друг к другу, что они превращаются в одно и то же float
значение 2−23. Вот почему нет разницы в вашем f2
а также f3
,
Есть разница между f1
а также f2
, но вы не напечатали достаточно цифр, чтобы отобразить его.
Вы спрашиваете: "Не должен ли float
ценность x + FLT_EPSILON
а также x - FLT_EPSILON
быть таким же? ", но ваш код не содержит x - FLT_EPSILON
,
Re: "Мой вопрос R
значение с плавающей запятой x
, что y
ценить это x + y
|| x - y
равняется тому же R
значение с плавающей запятой? " y
= 0. Вы хотели спросить, какое наибольшее значение y
что удовлетворяет условию? Это немного сложно.
Размер шага для числа x называется ULP of x, который мы можем рассматривать как функцию ULP (x). ULP выступает за единицу наименьшей точности. Это значение места наименьшей цифры в представлении с плавающей запятой для x. Это не константа; это функция х.
Для большинства значений, представляемых в формате с плавающей запятой, наибольшее y
то, что удовлетворяет вашему условию, равно ½ ULP (x) наименьшей цифры в представлении с плавающей запятой x и является четным, а если цифра нечетная, оно составляет чуть меньше ½ ULP (x). Эта сложность возникает из-за правила, согласно которому результаты арифметики округляются до ближайшего представимого значения, и в случае связи выбирается значение с четной младшей цифрой. Таким образом, добавление ½ ULP (x) к x приведет к равенству, которое округляется до x, если младшая цифра четная, но не округляется до x, если младшая цифра нечетная.
Однако для х, которые находятся на границе, где меняется ULP, наибольшее y
что удовлетворяет вашему условию ¼ ULP(x). Это происходит потому, что чуть ниже x (по величине) размер шага изменяется, и следующее число, меньшее x, равно половине шага x вместо обычного полного размера шага. Таким образом, вы можете пройти только половину к этому значению, прежде чем изменить результат вычитания, поэтому наиболее y
может быть ¼ ULP(х).
float f1 = 1.234567f;
float f2 = f1 + 1.192092897e-7f;
float f3 = f1 + 1.192092896e-7f;
printf("Inicial:\t%.20f\n", f1);
printf("Inicial:\t%.20f\n", f2);
printf("Inicial:\t%.20f\n\n", f3);
Выход:
Inicial: 1.23456704616546630000
Inicial: 1.23456716537475590000
Inicial: 1.23456716537475590000
Нет, ваши ожидания неверны
Во-первых printf
вызов, вы печатаете переменную f1 без эффекта, который просто 1.234567f
,
Float является 32
бит IEEE 754 с плавающей запятой одинарной точности: 1
немного за знак, 8
биты для показателя степени и 23
* для значения, то есть float имеет 7
десятичные цифры точности.
Увеличить printf
количество напечатанных цифр, чтобы увидеть больше, но после 7
цифры его просто шум:
#include <stdio.h>
int main(void) {
float f1 = 1.234567f;
float f2 = 1.234567f + 1.192092897e-7f;
float f3 = 1.234567f + 1.192092896e-7f;
printf("Inicial:\t%.16f\n", f1);
printf("Inicial:\t%.16f\n", f2);
printf("Inicial:\t%.16f\n\n", f3);
return 0;
}
Выход:
Inicial: 1.2345670461654663
Inicial: 1.2345671653747559
Inicial: 1.2345671653747559