Печать двойного переменного содержимого - PullRequest
2 голосов
/ 24 марта 2010

Я попробовал следующий фрагмент кода, и вывод меня удивляет:

#include <stdio.h>
#include <math.h>

int main()
{
            double num;
            unsigned char ch;

            ch = 19;
            num = 1.0E+20 ;
            num += ch * 1.0E+18;
            printf("E18 = %lf \n",num);
            printf("E18 = %e \n",num);

            num = 11.0E+21 ;
            num += ch * 1.0E+19;
            printf("E19 = %lf <------\n",num);
            printf("E19 = %e <------\n",num);

            num = 11.0E+22 ;
            num += ch * 1.0E+20;
            printf("E20 = %lf\n",num);
            printf("E20 = %e\n",num);

            num = 11.0E+23 ;
            num += ch * 1.0E+21;
            printf("E21 = %lf\n",num);
            printf("E21 = %e\n",num);

            num = 11.0E+24 ;
            num += ch * 1.0E+22;
            printf("E22 = %lf <------\n",num);
            printf("E22 = %e <------\n",num);
    return 0;
}

Вывод программы:

E18 = 119000000000000000000.000000 
E18 = 1.190000e+20 
E19 = 11190000000000000524288.000000 <------
E19 = 1.119000e+22 <------
E20 = 111900000000000001048576.000000
E20 = 1.119000e+23
E21 = 1119000000000000044040192.000000
E21 = 1.119000e+24
E22 = 11189999999999999366660096.000000 <------
E22 = 1.119000e+25 <------

Почему данные повреждены при печати в экспоненциальной форме в порядке

Ответы [ 5 ]

6 голосов
/ 24 марта 2010

Потому что вы теряете точность, когда числа становятся достаточно большими:

3 голосов
/ 24 марта 2010

Данные не повреждены; это просто, как значения с плавающей запятой работают на современных компьютерах. Представьте число с плавающей точкой как фиксированное количество цифр (мантисса) и другое число, указывающее, где должна быть размещена десятичная точка (показатель степени). Для более длинной и точной истории, Википедия - хорошее начало .

Поскольку число цифр мантиссы фиксировано, оно не может представлять крошечную дробь, которую вы просите здесь. Кроме того, поскольку все они в двоичном формате, десятичные числа не всегда могут быть представлены точно.

Экспоненциальная запись просто округляет последние несколько цифр, где число, как известно, является неточным, следовательно, ваши результаты.

0 голосов
/ 24 марта 2010

Вы видите неточность, присущую с плавающей запятой.

Некоторые преобразования printf гарантированно дают достаточно значимые цифры, чтобы однозначно идентифицировать печатаемый номер. Это подразумевает, что если есть какая-то неточность, вы увидите это. И наоборот, представление %e / %f по умолчанию скрывает неточность путем округления.

Насколько я знаю, %a (шестнадцатеричное число с плавающей запятой) - единственный способ достичь этого. Согласно спецификация POSIX , %lf определена так же, как и %f, то есть

l (ell)… не влияет на следующий спецификатор преобразования a, A, e, E, f, F, g или G.

Так что технически это ошибка в вашей стандартной библиотеке.

0 голосов
/ 24 марта 2010

Типы данных с плавающей запятой используют конечное число битов для представления определенного диапазона чисел. Однако между любыми двумя действительными числами m и n может быть бесконечное число значений. Итак, вы жертвуете точностью.

В экспоненциальной форме все выглядит хорошо, поскольку печатаются не все цифры.

В качестве теста попробуйте напечатать значение 0.2 с 10 десятичными разрядами, и вы увидите, что сохраненное значение больше похоже на 0.1999999 ....

0 голосов
/ 24 марта 2010

Двойные числа / числа с плавающей точкой теряют точность по мере увеличения - в дополнение к статье Википедии Туомас опубликовал еще один хороший вариант:

http://www.yoda.arachsys.com/csharp/floatingpoint.html

Он был нацелен на .NET, но принцип все еще применяется.

...