Числовая точность двойного типа в отладчике Visual C++ 2008 Express
Я использую Visual C++ 2008 Express Edition и когда я отлаживаю код:
double x = 0.2;
Я вижу в подсказке отладки на 0.20000000000000001
но:
typedef numeric_limits< double > double_limit;
int a = double_limit::digits10
дает мне: а = 15
Почему результаты в отладчике длиннее обычной точности C++? На чем основана эта странная точность?
Мой процессор - Intel Core 2 Duo T7100
3 ответа
То, что вы видите, вызвано тем фактом, что действительные числа (с плавающей запятой) не могут быть выражены с идеальной точностью и точностью в двоичных компьютерах. Это факт жизни. Вместо этого компьютеры приближают значение и сохраняют его в памяти в определенном формате.
В случае большинства современных машин (включая любые машины, на которых работает MSVC Express), этот формат - IEEE 754.
Короче говоря, вот как реальные цифры хранятся в IEEE 754: есть один знаковый бит, 8 битов экспоненты и 23 бита дроби (для float
тип данных -- doubles
используйте больше битов соответственно, но формат тот же). Из-за этого вы никогда не сможете достичь идеальной точности и точности. К счастью, вы можете достичь высокой точности и точности практически для любого приложения, включая критические финансовые системы и научные системы.
Вам не нужно знать все, что нужно знать о IEEE754, чтобы использовать плавающие точки в вашем коде. Но есть несколько вещей, которые вы должны знать:
1) Вы никогда не сможете сравнить 2 значения с плавающей запятой на равенство из-за ошибки округления, присущей вычислению и хранению с плавающей запятой. Вместо этого вы должны сделать что-то вроде этого:
double d = 0.2;
double compare = 0.000000001;
double d2 = something;
if( (d - d2 < compare) && (d2 - d < compare) )
{
// numbers are equal
}
2) Соединение ошибок округления. Чем больше раз вы выполняете операции со значением с плавающей запятой, тем больше потеря точности.
3) Вы не можете добавить две плавающие точки совершенно разной величины. Например, вы не можете добавить 1,5x10^30 и 1,5x10^-30 и ожидать 60 цифр точности.
Вы должны прочитать это: Что каждый ученый должен знать об арифметике с плавающей точкой
Точное значение, что двойной литерал 0.2
дает вам 0.200000000000000011102230246251565404236316680908203125.
Большинство функций, которые выводят удваивается после определенного количества десятичных цифр, поэтому вы находитесь в иллюзии, что 0.2
на самом деле дает 0,2
Вот как я получил точное значение:
public static void main(String[] args)
{
System.out.println(new java.math.BigDecimal(0.2));
}