"плавати" проти "подвійної" точності


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 значущих цифр?

Відповіді:


146

Номери з плаваючою комою в C використовують кодування IEEE 754 .

Цей тип кодування використовує знак, означення та показник.

Через таке кодування багато номерів матимуть невеликі зміни, щоб дозволити їх зберігати.

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

Одинична точність (поплавок) дає вам 23 біта значень, 8 біт експонента та 1 біт знаків.

Подвійна точність (подвійна) дає 52 біти значущості, 11 біт експонента та 1 біт знаків.


4
C99 робить, раніше це було залежно від компілятора.
Алан Геленсе

21
-1 Це твердження явно неправдиве: "Через таке кодування ви ніколи не можете гарантувати, що у вас не зміниться значення".
R .. GitHub СТОП ДОПОМОГАЄТЬСЯ

16
@Alan: C99 не вимагає плаваючої точки IEEE; це просто рекомендує.
R .. GitHub СТОП ДОПОМОГАЙТЕ

4
@Alan: R .. правильно; Додаток F (який визначає прив'язки IEEE-754) є нормативним, але діє лише в тому випадку, якщо реалізація визначає __STDC_IEC_559__. Реалізація, яка не визначає, що макрос не може відповідати IEEE-754.
Стівен Канон

12
@Alan: Під IEEE 754, це легко гарантувати , що немає ніяких змін в значеннях 0.5, 0.046875або в 0.376739501953125порівнянні з їх десятковими уявленнями. (Всі ці Диадические з чисельник раціонального фитингом в мантиссу і підстава 2 логарифмом знаменника фитинга в показнику.)
R .. GitHub СТОП допоміг ДВС

42

Чи є у парних пар 16 завжди значущих фігур, а у поплавців завжди 7 значущих фігур?

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

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

Чому парні не мають 14 значущих цифр?

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


15

float: 23 біта знамення, 8 біт експонента та 1 біт знака.

подвійний: 52 біта знамення, 11 біт показника і 1 біт знака.


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 для float52 - 12 для double), тому точність більш ніж у два рази.

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


Друкарська помилка? Для C89 потрібен епсилон максимум 1E-9для double, а не 1E-7.
Rufflewind

10

Поплавок має 23 біти точності, а подвійний - 52.


Детальніше: binary64 має 53-бітовий значний (52 явно зберігається) binary32 має 24 біт (23 явно зберігається).
chux

4

Це не зовсім подвійна точність через те, як працює IEEE 754 , а також тому, що двійкові не дуже добре перекладаються на десяткову. Погляньте на стандарт, якщо вас цікавить.


4

float означає число з плаваючою комою. В C тип даних поплавця використовується в тих випадках, коли точність загальної кількості цифр становить 7. Для, наприклад: - десяткової цифри. 12.3546987 не можна зберігати у плавці, оскільки в ньому є 9 цифр. Вихід буде показано як 12.354699, тобто перші 7 цифр будуть показані як введені на вході, а восьма цифра буде округлена. Тип поплавця може представляти значення в межах від приблизно 1,5 x 10 ^ (- 45) до 3,4 x 10 ^ (38). З точки зору розподілу пам’яті, float - це одноточний, 32-бітний тип даних з плаваючою точкою.

На відміну від поплавця, подвійний має точність від 15 до 16 цифр. Діапазон подвійних становить від 5,0 × 10 ^ (- 345) до 1,7 × 10 ^ (308). У плані розподілу байтів подвійний - це 64-бітні дані з плаваючою комою. тип.

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

Отже, краща дубль над поплавком для більшої точності даних.

Сподіваюся, це допомагає.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.