Двойной IEEE имеет 53 значащих бита (это значение DBL_MANT_DIG
в <cfloat>
).Это примерно 15,95 десятичных цифр (log10 (2 53 ));реализация устанавливает DBL_DIG
на 15, а не на 16, потому что оно должно округляться.Таким образом, у вас есть почти дополнительная десятичная цифра точности (помимо того, что подразумевается DBL_DIG==15
) из-за этого.
Функция nextafter()
вычисляет ближайшее представимое число для данного числа;его можно использовать, чтобы показать, насколько точным является данное число.
Эта программа:
#include <cstdio>
#include <cfloat>
#include <cmath>
int main() {
double x = 1.0/7.0;
printf("FLT_RADIX = %d\n", FLT_RADIX);
printf("DBL_DIG = %d\n", DBL_DIG);
printf("DBL_MANT_DIG = %d\n", DBL_MANT_DIG);
printf("%.17g\n%.17g\n%.17g\n", nextafter(x, 0.0), x, nextafter(x, 1.0));
}
выдает мне вывод в моей системе:
FLT_RADIX = 2
DBL_DIG = 15
DBL_MANT_DIG = 53
0.14285714285714282
0.14285714285714285
0.14285714285714288
(Вы можете заменить %.17g
, скажем, %.64g
, чтобы увидеть больше цифр, ни одна из которых не является значимой.)
Как видите, последняя отображаемая десятичная цифра изменяется на 3 с каждым последующим значением.Тот факт, что последняя отображаемая цифра 1.0/7.0
(5
) соответствует математическому значению, в значительной степени совпадает;это была удачная догадка.И правильная округленная цифра - 6
, а не 5
.Замена 1.0/7.0
на 1.0/3.0
дает следующий вывод:
FLT_RADIX = 2
DBL_DIG = 15
DBL_MANT_DIG = 53
0.33333333333333326
0.33333333333333331
0.33333333333333337
, который показывает примерно 16 десятичных цифр точности, как и следовало ожидать.