Вчера я задал вопрос о том, почему я теряю точность арифметики с плавающей запятой. Я получил ответ о том, что это произошло из-за того, что промежуточные результаты хранятся в регистрах 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
мы получаем правильный ответ из значения с более низкой точностью. Конечно, если более низкое значение точности может дать правильный ответ, то более высокое значение точности также должно дать правильный ответ? Это как-то связано с «двойным округлением»?
Заранее спасибо, это совершенно новая тема для меня, поэтому я немного борюсь.
long double
в таких расчетах ... - person Rontogiannis Aristofanis   schedule 16.03.2013