Точность в поплавках C

Обычно мы говорим, что число с плавающей точкой имеет точность 6 цифр после десятичной точки. Но если мы храним большое число порядка 10^30, мы не получим 6 цифр после десятичной точки. Так правильно ли говорить, что числа с плавающей точкой имеют точность 6 цифр после десятичной точки?

4 ответа

Решение

"6 цифр после десятичной точки" не является обязательным, и ваш пример является хорошей демонстрацией этого.

Это точная спецификация float тип данных.

Точность float 24 бита. Есть 23 бита, обозначающих дробь после двоичной точки, плюс есть также "неявный ведущий бит", согласно онлайн-источнику. Это дает в общей сложности 24 значащих бита.

Следовательно, в десятичных цифрах это примерно:

24 * log (2) / log (10) = 7,22

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

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


Большинство систем в наши дни используют формат IEE с плавающей запятой для представления чисел в C. Однако, если у вас что-то необычное, стоит проверить. IEE одинарной точности float номера состоят из трех частей:

  • Знаковый бит (это число положительное или отрицательное)
  • (Обычно также подписанный) показатель
  • Фракция (число до применения показателя степени)

Как и следовало ожидать, все это хранится в двоичном виде.


Сколько значимых цифр?

Если вы используете числа IEE-754, "сколько значащих цифр", вероятно, не простой способ думать об этом, потому что точность измеряется в двоичных значащих цифрах, а не в десятичных. float s имеют только 23 бита точности для дробной части, но поскольку существует неявный начальный бит (если только дробная часть не равна нулю, что указывает на конечное значение 1), существует 24 эффективных бита точности.

Это означает, что есть 24 значащие двоичные цифры, что не переводит в точное число десятичных значащих цифр. Вы можете использовать формулу 24 * log(2) / log(10), чтобы определить, что есть 7,225 цифр десятичной точности, что не очень хороший ответ на ваш вопрос, поскольку есть числа из 24 значащих двоичных цифр, которые только иметь 6 значащих десятичных цифр.

Таким образом, числа с плавающей запятой одинарной точности имеют 6-9 значащих десятичных знаков точности, в зависимости от числа.

Интересно, что вы также можете использовать эту точность для вычисления наибольшего последовательного целого числа (считая от нуля), которое вы можете успешно представить в плавающей запятой с одинарной точностью. Это 2^24, или 16 777 216. Вы можете точно хранить большие целые числа, но только если они могут быть представлены в 24 значащих двоичных цифрах.


Дальнейшие мелочи: ограниченный размер компонента фракции - это то же самое, что вызывает это в Javascript:

> console.log(9999999999999999);
10000000000000000

Числа Javascript всегда представлены как числа с плавающей запятой двойной точности, которые имеют точность 53 бита. Это означает, что между 2^53 и 2^54 могут быть представлены только четные числа, потому что последний бит любого нечетного числа теряется.

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

Языковые юристы скажут, что точная ширина float не определено стандартом C и поэтому зависит от реализации, но на любой платформе вы, вероятно, столкнетесь с C float означает число с одинарной точностью IEEE754.

IEEE754 указывает, что число с плавающей запятой находится в научной нотации: (-1) s × 2 e × m
где s имеет ширину один бит, e имеет ширину восемь бит, а m имеет ширину двадцать три бита. Математически, m имеет ширину 24 бита, потому что всегда предполагается, что старший бит равен 1.

Таким образом, максимальное количество десятичных цифр, которое может быть аппроксимировано этим представлением: log 10 (2 24) = 7,22. Это приблизительно семь значащих десятичных цифр и показатель степени в диапазоне от 2 -126 до 2 127.

Обратите внимание, что показатель степени измеряется отдельно. Это точно так же, как если бы вы использовали обычные научные обозначения, например: "Человек весит 72,3 килограмма = 7,23 × 10 4 грамма". Обратите внимание, что здесь есть три значащие цифры, что означает, что число является точным с точностью до 100 граммов. Но есть также показатель, который является совершенно другим числом. Вы можете иметь очень большой показатель степени с очень небольшим количеством значащих цифр, например, "Солнце весит 1,99 × 10 33 грамма". Большое число, несколько цифр.

Одним словом, число с плавающей запятой может хранить около 7-8 значащих десятичных цифр. Позвольте мне проиллюстрировать это на примере:

1234567001.00
         ^
         +---------------- this information is lost

.01234567001
           ^ 
           +-------------- this information is lost

В основном, float хранит два значения: 1234567 и положение десятичной точки.

Теперь это упрощенный пример. Float хранит двоичные значения вместо десятичных. 32-разрядное число с плавающей запятой IEEE 754 имеет место для 23 "значащих битов" (плюс первый, который всегда принимается равным 1), что соответствует примерно 7-8 десятичным цифрам.

 1234567001.00 (dec) =

 1001001100101011111111101011001.00 (bin)  gets rounded to

 1001001100101011111111110000000.00 =
  |    23 bits           |

 1234567040.00 (dec)

И это именно то, что производит C:

void main() {
    float a = 1234567001;
    printf("%f", a);      // outputs 1234567040
}
Другие вопросы по тегам