Int main(void)
{
float aboat = 32000.0;
double abet = 2.14e9;
long double dip = 5.32e-5;
printf("%f может быть записано как %e\n", aboat, aboat);
// для вывода следующей строки требуется компилятор,
// поддерживающий С99 или более поздний стандарт
printf("И его %а в шестнадцатеричной, представляющей степени 2, форме записи\п", aboat);
printf("%f может быть записано как %e\n", abet, abet);
printf("%Lf может быть записано как %Le\n", dip, dip);
return 0;
}
Ниже приведен вывод:
может быть записано как 3.200000е+04
И его 0xl.f4p+14 в шестнадцатеричной, представляющей степени 2, форме записи 2140000000может быть записано как 2.140000е+09
0.000053 может быть записано как 5.320000е — 05
Этот пример иллюстрирует стандартный вывод.
Переполнение и потеря значимости в операциях с плавающей запятой
Предположим, что наибольшее возможное значение типа float равно примерно 3.4Е38, и нужно выполнить следующие операции:
float toobig = 3.4Е38 * 100.Of;
printf("%e\n", toobig);
Что произойдет? Это пример переполнения, когда в результате вычислений получается слишком большое число, чтобы его можно было правильно представить. Поведение системы в таких случаях обычно не определено, но в рассматриваемой ситуации переменной toobig присваивается специальное значение, которое обозначает бесконечность, и функция printf () отображает либо inf, либо infinity (или какую- то другую вариацию на эту тему).
А что можно сказать о делении очень малых чисел? Здесь ситуация более сложная. Вспомните, что число типа float хранится в виде сочетания показателя степени и значащей части, или мантиссы. В рассматриваемом случае это число, имеющее минимально возможный показатель степени, а также наименьшее значение, которое использует все доступные биты, отведенные для представления мантиссы. Это будет наименьшее число, представленное с наибольшей точностью, доступной для типа float. Теперь разделим его на 2. Обычно это приводит к уменьшению показателя степени, но в данном случае показатель уже достиг своего нижнего предела. Происходит сдвиг битов мантиссы вправо, с освобождением первой позиции и потерей последней двоичной цифры. Аналогичная картина возникает, если выбрать 10 в качестве основания системы счисления, взять число с четырьмя значащими цифрами, например,
1234Е-10, и разделить его на 10, получив в итоге 0.0123Е-10. Вы получите результат, но в процессе деления потеряете цифру. Эта ситуация называется потерей значимости, а значения с плавающей запятой, которые утратили полную точность типа, в языке С называются субнормальными. Таким образом, деление наименьшего положительного значения с плавающей запятой на 2 дает субнормальное значение. Деление на достаточно большое значение приведет к потере всех цифр, и вы получите в результате 0. В настоящее время библиотека С предоставляет функции, которые позволяют проверить, не приведут ли вычисления к субнормальным значениям.
Существует еще одно специальное значение с плавающей запятой: NaN (not-a-number — не число). Например, вы передаете функции asin () некоторое значение, а она возвращает угол, для которого переданное значение является синусом. Однако значение синуса не может быть больше 1, поэтому функция не определена для значений, превышающих 1. В таких случаях функция возвращает значение NaN, которое функция printf () отображает в виде nan, NaN или каким-то похожим образом.
Ошибки округления данных с плавающей запятой
Возьмите некоторое число, прибавьте к нему 1 и затем отнимите от суммы исходное число. Что вы получите в результате? Вы получите 1. Тем не менее, вычисления с плавающей запятой вроде показанного ниже могут дать другой результат:
/* floaterг.с — демонстрирует ошибку округления */
#include <stdio.h>
