'float' против 'двойной' точности

155

Код

float x  = 3.141592653589793238;
double z = 3.141592653589793238;
printf("x=%f\n", x);
printf("z=%f\n", z);
printf("x=%20.18f\n", x);
printf("z=%20.18f\n", z);

даст вам выход

x=3.141593
z=3.141593
x=3.141592741012573242
z=3.141592653589793116

где на третьей строке выводится 741012573242мусор, а на четвертой строке 116мусор. У двойников всегда есть 16 значащих цифр, а у чисел с плавающей запятой всегда 7 значащих цифр? Почему у двойников 14 значащих цифр?

Foo
источник

Ответы:

146

Числа с плавающей точкой в ​​C используют кодировку IEEE 754 .

Этот тип кодирования использует знак, значение и показатель степени.

Из-за этой кодировки многие числа будут иметь небольшие изменения, чтобы их можно было сохранить.

Кроме того, число значащих цифр может немного измениться, поскольку это двоичное представление, а не десятичное.

Одинарная точность (с плавающей запятой) дает вам 23 бита значения, 8 битов показателя степени и 1 знаковый бит.

Двойная точность (двойная) дает вам 52 бита значения, 11 битов показателя степени и 1 знаковый бит.

Алан Гелейнсе
источник
4
C99 делает, ранее это было до компилятора.
Алан Гелейнсе
21
-1 Это утверждение явно ложно: «Из-за этой кодировки вы никогда не сможете гарантировать, что у вас не будет изменений в вашей ценности».
R .. GitHub ОСТАНОВИТЬ ЛЬДА
16
@Alan: C99 не требует IEEE с плавающей запятой; он просто рекомендует это.
R .. GitHub ОСТАНОВИТЬ ЛЬДА
4
@ Алан: R .. правильно; Приложение F (которое определяет привязки IEEE-754) является нормативным, но действует только в том случае, если реализация определяет __STDC_IEC_559__. Реализация, которая не определяет этот макрос, свободна и не соответствует IEEE-754.
Стивен Кэнон
12
@Alan: Под IEEE 754, это легко гарантировать , что нет никаких изменений в значениях 0.5, 0.046875или в 0.376739501953125сравнении с их десятичными представлениями. (Это все диадические рациональные числа с числовой аппроксимацией в мантиссе и логарифмом по основанию 2 знаменательной аппроксимации в экспоненте.)
R .. GitHub STOP HELPING ICE
42

У двойников всегда есть 16 значащих цифр, а у чисел с плавающей запятой всегда 7 значащих цифр?

Нет. Двойники всегда имеют 53 значащих бита, а числа с плавающей запятой всегда имеют 24 значащих бита (за исключением денормалов, бесконечностей и значений NaN, но они являются предметами для другого вопроса). Это двоичные форматы, и вы можете четко говорить только о точности их представления в терминах двоичных цифр (битов).

Это аналогично вопросу о том, сколько цифр может быть сохранено в двоичном целом числе: 32-разрядное целое число без знака может хранить целые числа длиной до 32 бит, что точно не соответствует ни одному количеству десятичных цифр: все целые числа до Можно сохранить 9 десятичных цифр, но также можно сохранить множество 10-значных чисел.

Почему у двойников 14 значащих цифр?

Двойное кодирование использует 64 бита (1 бит для знака, 11 бит для показателя степени, 52 явных значащих бита и один неявный бит), что в два раза больше количества бит, используемых для представления числа с плавающей запятой (32 бита).

Стивен Кэнон
источник
15

число с плавающей запятой: 23 бита значения, 8 битов показателя степени и 1 знаковый бит.

double: 52 бита значений, 11 битов показателя степени и 1 знаковый бит.

abe312
источник
11

Обычно это основано на значимых показателях как показателя степени, так и значимости в базе 2, а не в базе 10. Однако из того, что я могу сказать в стандарте C99, нет определенной точности для чисел с плавающей запятой и двойных чисел (кроме того факта, что 1 и 1 + 1E-5/ 1 + 1E-7различимы [ floatи doubleпокорно]). Тем не менее, число значащих цифр оставлено на усмотрение разработчика (а также то, какую базу они используют внутри, поэтому, другими словами, реализация может принять решение сделать это на основе 18 цифр точности в базе 3). [1]

Если вам нужно знать эти значения, константы FLT_RADIXи FLT_MANT_DIGDBL_MANT_DIG/ LDBL_MANT_DIG) определены в файле float.h.

Причина, по которой он называется a, doubleзаключается в том, что количество байтов, используемых для его хранения, вдвое больше числа с плавающей запятой (но это включает как показатель степени, так и значение). Стандарт IEEE 754 (используемый большинством компиляторов) выделяет относительно больше битов для значения и, чем для показателя степени (от 23 до 9 для floatпротив 52 до 12 для double), поэтому точность более чем удвоена.

1: Раздел 5.2.4.2.2 ( http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf )

user470379
источник
Опечатка? С89 требует эпсилон максимум 1E-9для double, а не 1E-7.
Rufflewind
10

У поплавка 23 точности, а у двойника 52.

Крис Нэш
источник
Подробно: двоичная 64 имеет 53-разрядную значащую (52 явно хранятся) двоичная32 имеет 24-разрядную (23 явно хранится).
chux - Восстановить Монику
4

Это не совсем двойная точность из-за того, как работает IEEE 754 , а также из-за того , что двоичный код не очень хорошо переводит в десятичную. Посмотрите на стандарт, если вам интересно.

user541686
источник
4

float обозначает число с плавающей запятой. В C тип данных с плавающей запятой используется в тех случаях, когда точность общего количества цифр равна 7. Например: - десятичное число. 12.3546987 не может быть сохранен в float, потому что он имеет в общей сложности 9 цифр. Выходные данные будут показаны как 12.354699, т.е. первые 7 цифр будут показаны как введенные на входе, а 8-ая цифра будет округлена. Тип float может представлять значения в диапазоне приблизительно от 1,5 x 10 ^ (- 45) до 3,4 x 10 ^ (38). С точки зрения распределения памяти, float - это 32-битный тип данных с плавающей запятой с одинарной точностью.

В отличие от float, double имеет точность от 15 до 16 цифр. Диапазон double - от 5,0 × 10 ^ (- 345) до 1,7 × 10 ^ (308). С точки зрения распределения байтов double - это 64-битные данные с плавающей запятой тип.

Проблема возникает в его использовании. Float или double не влияет на printf, но в случае scanf должен использоваться соответствующий тип данных в зависимости от общего числа no. цифр в плавающем нет. это должно быть прочитано от входа.

Следовательно, double предпочтительнее, чем float, для более высокой точности данных.

Надеюсь это поможет.

Vineeth Krishna K
источник