Плавающее представление следует за методом, подобным тому, что мы используем в повседневной жизни, и мы называем экспоненциальное представление.Это число, использующее число цифр, которое, по нашему мнению, будет достаточно для реалистического представления значения, которое мы называем мантиссой, или значащего, которое мы умножим до базового или основательного значения, возведенного в степень, которую мы называем экспонентой.Проще говоря:
num*base^exp
Обычно мы используем 10 в качестве основы, потому что у нас в руках 10 пальцев, поэтому мы привыкли к числам вроде 1e2
, то есть 100=1*10^2
.
Конечно, мы сожалеем об использовании экспоненциального представления для столь малых чисел, но мы предпочитаем использовать его при работе с очень большими числами или, что лучше, когда у нашего числа есть количество цифр, которое мы считаем достаточным для представлениясущность, которую мы ценим .
Правильным количеством цифр может быть количество, которое мы можем обработать умом, или то, что требуется для инженерного приложения.Когда мы решили, сколько цифр нам нужно, мы больше не будем заботиться о том, насколько привязанным к реальному значению будет числовое представление, которое мы собираемся обработать.Т.е. для числа, подобного 123456.789e5
, подразумевается, что, сложив 99
единицу, мы можем допустить округленное представление и в любом случае считать его приемлемым, если нет, нам следует изменить представление и использовать другое с соответствующим количеством цифр, как в 12345678900
.
На компьютере, когда вам приходится работать с очень большими числами, которые не укладываются в стандартное целое число, или когда вам нужно представлять действительное число (с десятичной частью), правильный выборfloating
или double
представление с плавающей запятой.Он использует тот же макет, который мы обсуждали выше, но основание 2 вместо 10 .Это потому, что компьютер может иметь только 2 пальца, состояния 0
или 1
.Вот формула, которую мы использовали ранее, чтобы представить 100, стать:
100100*2^0
Это все еще не реальное представление с плавающей запятой, но дает идею.Теперь рассмотрим, что в компьютере формат с плавающей запятой стандартизирован и для стандартного числа с плавающей запятой, согласно IEE-754, он использует в качестве схемы памяти (мы увидим, почему для мантиссы предполагается еще 1 бит), 23 бита длямантисса, 1 бит для знака и 8 бит для показателя степени, смещенного на -127 (это просто означает, что он будет находиться в диапазоне от -126
до +127
без необходимости знакового бита, а значения 0x00
и 0xff
зарезервированыдля специального значения).
Теперь рассмотрим использование 0 в качестве показателя степени, это означает, что значение 2^exponent=2^0=1
, умноженное на мантиссу, дает такое же поведение целого числа в 23 бита.Это означает, что при увеличении числа, как в:
float f = 0;
while(1)
{
f +=1;
printf ("%f\n", f);
}
Вы увидите, что напечатанное значение линейно увеличивается на единицу, пока оно не насытит 23 бита, и показатель не станет расти.
Еслиоснование или основание нашего числа с плавающей запятой было бы равно 10, мы бы увидели увеличение каждые 10 циклов для первых 100 (10 ^ 2) значений, чем увеличение на 100 для следующих 1000 (10 ^ 3) значений искоро.Вы видите, что это соответствует * усечению **, которое мы должны сделать из-за ограниченного числа доступных цифр.
Такое же явление будет наблюдаться при использовании двоичной базы, только изменения происходят при степенях 2интервал.
То, что мы обсуждали до сих пор, называется денормализованной формой с плавающей запятой, обычно используется аналог нормализованный .Последнее просто означает, что существует 24-й бит, не сохраненный, то есть всегда 1
.В плоских словах мы не будем использовать показатель степени 0
для числа, меньшего 2^24
, но мы сместим его (умножим на 2) до достижения MSbit==1
значения 24-го бита, чем показатель степени настроен на такое значение.отрицательное значение, которое заставляет преобразование сдвинуть число обратно к его первоначальному значению.
Помните зарезервированное значение показателя степени, о котором мы говорили выше?Ну, exponent==0x00
означает, что у нас есть денормализованное число.exponent==0xff
указывает nan
(не число) или +/- бесконечность, если mantissa==0
.
Теперь должно быть ясно, что когда число, которое мы выражаем, выходит за пределы 24 бит значащего (мантисса), нам следует ожидать приближения реального значения в зависимости от того, как далеко мы находимся от 2^24
.
Теперь номер, который вы используете, находится на грани 2^24=16,277,216
:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|0|0|1|0|1|1|0|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1| = 16,277,215
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
s\______ _______/\_____________________ _______________________/
i v v
g exponent mantissa
n
Теперь увеличиваясь на 1, мы имеем:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|0|0|1|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0| = 16,277,216
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
s\__ exponent __/\_________________ mantissa __________________/
Обратите внимание, что мы включили 1
24-й бит, но с этого момента мы находимся выше 24-битного представления, и каждое возможное дальнейшее представление выполняется с шагом 2^1=2
. Просто продвиньтесь на 2 или можете представить только четные числа (кратные 2^1=2
). То есть установив в 1 менее значимый бит, мы имеем:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|0|0|1|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1| = 16,277,218
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
s\__ exponent __/\_________________ mantissa __________________/
Снова увеличивается:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|0|0|1|0|1|1|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|0| = 16,277,220
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
s\__ exponent __/\_________________ mantissa __________________/
Как видите, мы не можем точно представить 16 277 219. В вашем коде:
// This will print 16777216, because 1 increment isn't enough to
// increase the significant that can express only intervals
// that are > 2^1
printf("16777217 as float is %.1f\n",(float)16777217);
// This will print 16777220, because an increment of 3 on
// the base 16777216=2^24 will trigger an exponent increase rounded
// to the closer exact representation
printf("16777219 as float is %.1f\n",(float)16777219);
Как уже было сказано выше, выбор числового формата должен быть подходящим для использования, с плавающей запятой - это всего лишь приблизительное представление действительного числа , и, безусловно, наша обязанность тщательно использовать правильный тип.
В случае, если нам нужна большая точность, мы можем использовать double
или целое число long long int
.
Просто ради полноты я бы добавил несколько слов о приближенном представлении неприводимых чисел. Эти числа не делятся на доли 2, поэтому представление в формате с плавающей запятой всегда будет не точным и должно быть округлено до правильного значения во время преобразования в десятичное представление.
Подробнее см .:
Онлайн-апплеты: