Вчера я спросил question о том, почему я терял точность в арифметике с плавающей запятой. Я получил ответ о том, как это произошло из-за того, что промежуточные результаты проводятся в регистре x87. Это было полезно, но некоторые детали еще ускользают от меня. Вот вариант программы, представленной в предыдущем вопросе, я использую VC++ 2010 Express в режиме отладки.Точность с плавающей запятой снова
int main()
{
double x = 1.8939201459282359e-308; /* subnormal number */
double tiny = 4.9406564584124654e-324; /* smallest IEEE double */
double scale = 1.6;
double temp = scale*tiny;
printf("%23.16e\n", x + temp);
printf("%23.16e\n", x + scale*tiny);
}
Это выводит
1.8939201459282369e-308
1.8939201459282364e-308
Первое значение является правильным в соответствии со стандартом IEEE. Предоставление переменной scale
значения 2.0 дает правильное значение для обоих вычислений. Я понимаю, что temp
в первом вычислении является субнормальным значением и, следовательно, теряет точность. Я также понимаю, что значение scale*tiny
хранится в регистре x87, который имеет больший диапазон экспоненциальности и поэтому это значение имеет большую точность, чем temp
. Я не понимаю, что при добавлении значения в x
мы получаем правильный ответ от значения меньшей точности. Разумеется, если значение более низкой точности может дать правильный ответ, то более точное значение точности также должно дать правильный ответ? Это как-то связано с «двойным округлением»?
Заранее спасибо, это совершенно новая тема для меня, поэтому я немного борюсь.
Возможно, все верно, но мне это совершенно не очевидно: * Конечно, если значение более низкой точности может дать правильный ответ, то более точное значение точности должно также дать правильный ответ? * – NPE
Если бы я был вами , Я бы использовал 'long double' в таких вычислениях ... –
Как мы узнаем, что число меньшей точности не имеет случайного значения в последней цифре? Всегда есть 10% шанс попасть в ожидаемый. –