Скільки значущих цифр має поплавці та подвійні в Java?


83

Чи має поплавок 32 двійкові цифри, а подвійний - 64 двійкові цифри? Документація була надто складною, щоб зрозуміти її.

Чи всі біти перекладаються на значущі цифри? Або розташування десяткової коми займає деякі біти?


2
Чи всі ці біти перекладаються на значущі цифри? Або розташування десяткової коми займає частину бітів?
Eamon Moloney

@ user1774214 числа з плаваючою комою взагалі не кодуються як цілі числа. подивіться на посилання, яке я даю. Ви повинні розуміти, наприклад, що точність не рівномірна.
Denys Séguret

@dystroy Я не впевнений, що ви маєте на увазі під “точністю не є однаковою”. Це досить рівномірно 53 і 24 біти точності, якщо ви не маєте на увазі денормалів.
Паскаль Куок,

2
@PascalCuoq є більшою точністю для менших чисел. Коли показник змінюється (або точка плаває) навколо, мантиса продовжує представляти однакову кількість цифр. Отже, якщо число велике, мантиса "не може досягти" нижчих значущих цифр, тим самим надаючи меншу точність.
Vituel

3
@Virtuel Точність 53 біти. Це те, що ми називаємо точністю. Ви, здається, думаєте про абсолютну точність чи щось інше.
Паскаль Куок,

Відповіді:


108

float : 32 біти (4 байта), де 23 біти використовуються для мантиси (близько 7 десяткових цифр). Для експоненти використовується 8 бітів, тому плаваючий засіб може «переміщати» десяткову крапку вправо або вліво, використовуючи ці 8 бітів. Це дозволяє уникнути зберігання великої кількості нулів у мантисі, як у 0,0000003 (3 × 10 -7 ) або 3000000 (3 × 10 7 ). В якості знакового біта використовується 1 біт.

double : 64 біти (8 байт), де 52 біти використовуються для мантиси (приблизно 16 десяткових цифр). Для експоненти використовується 11 бітів, а 1 біт - знаковий біт.

Оскільки ми використовуємо двійкові (лише 0 та 1), один біт у мантисі має неявний 1 (як float, так і double використовують цей фокус), коли число не дорівнює нулю.

Крім того, оскільки все є у двійковому (мантисі та експонентах) перетворення в десяткові числа, як правило, не є точними. Такі числа, як 0,5, 0,25, 0,75, 0,125 зберігаються точно, але 0,1 - ні. Як казали інші, якщо вам потрібно точно зберігати центи, не використовуйте float або double, використовуйте int, long, BigInteger або BigDecimal.

Джерела:

http://en.wikipedia.org/wiki/Floating_point#IEEE_754:_floating_point_in_modern_computers

http://en.wikipedia.org/wiki/Binary64

http://en.wikipedia.org/wiki/Binary32


що ви маєте на увазі 6 до 9? як це може змінитися? тож, якщо я кілька разів запущу якийсь код, який має 8 десяткових цифр, наприклад 0,000000001, я отримаю різні результати? це ти маєш на увазі?
Aequitas,

2
Деякі числа можна представити точніше у двійковому вигляді, ніж інші. Ви можете бачити різницю в 0,125 (1/8, вісім - це степінь удвох) та 0,1 (1/10, десять - це не вдвічі). Перший має більше (десяткових) цифр, але представлений точно. Тож може бути, що число з 6 десятковими цифрами має більші помилки округлення, ніж інше число з 8 цифрами.
marcus

9
15,9 десяткових цифр для doubleі 7,2 для float, тобто 15 і 7. Деякі більші числа можуть бути представлені в кожному випадку, і жодне з них не відноситься до дробів, але в ньому немає "середнього значення", і жодне з ваших джерел не говорить інакше.
user207421

1
Якщо вам не подобається слово середнє, запропонуйте редагувати. Спочатку його не додав я, його редагував хтось інший ... (і я справді не бачив необхідності в цьому редагуванні).
marcus

4
Цікаво, що насправді є одна цифра точності більше, ніж зберігається в мантисі / знаку. 23 і 52 біти зберігаються для float та double, відповідно, але оскільки числа нормалізовані, ми можемо прийняти провідний 1-біт, а потім залишити його поза. Ось чому ефективна точність становить 24 та 53 біти відповідно. Точні десяткові точності обчислюються log10 (2 ^ 24) = 7,22 та log10 (2 ^ 53) = 15,95
Джорджі

32

32-розрядний поплавок має приблизно 7 цифр точності, а 64-розрядний подвійний - близько 16 цифр точності

Довга відповідь:

Числа з плаваючою комою мають три складові:

  1. Знаковий біт, щоб визначити, чи є число позитивним чи негативним.
  2. Показник степеня, щоб визначити величину числа.
  3. Дріб, який визначає відстань між двома показниками ступеня. Це іноді називають "значенням, мантисою або коефіцієнтом"

По суті, це вдається sign * 2^exponent * (1 + fraction). «Розмір» числа, його показника, для нас не має значення, оскільки він лише масштабує значення частки частки. Знаючи, що log₁₀(n)дає число цифр n, †, ми можемо визначити точність числа з плаваючою точкою за допомогою log₁₀(largest_possible_fraction). Оскільки кожен біт у поплавці зберігає 2 можливості, двійкове число nбітів може зберігати число до 2ⁿ - 1(загальна кількість 2ⁿ значень, де одне із значень дорівнює нулю). Це стає трохи волосатішим, оскільки виявляється, що числа з плаваючою комою зберігаються з одним бітом дробу менше, ніж вони можуть використовувати, оскільки нулі представлені спеціально, а всі ненульові числа мають принаймні один ненульовий двійковий біт. ‡

Поєднуючи це, цифри точності для числа з плаваючою точкою складають log₁₀(2ⁿ), де n- кількість бітів частки числа з плаваючою точкою. 32-розрядний поплавок має 24 біти дробу для ≈7,22 десяткових цифр точності, а 64-бітний подвійний - 53 біти дробу для ≈15,95 десяткових цифр точності.

Щоб отримати докладнішу інформацію про точність із плаваючою точкою, ви можете прочитати про концепцію машини epsilon .


n ≥ 1Принаймні - для інших чисел ваша формула буде виглядати більше ⌊log₁₀(|n|)⌋ + 1.

‡ “Це правило по-різному називають умовою провідного біта, неявною умовою бітів або умовою прихованих бітів”. ( Вікіпедія )


17

Зі специфікації Java :

Типи з плаваючою комою бувають з плаваючою комою та подвійними, які концептуально пов’язані зі значеннями та операціями IEEE 754 з одноточною 32-бітною та подвійною точністю 64-бітного формату, як зазначено у IEEE Standard for Binary Floating-Point Arithmetic, ANSI / IEEE Стандарт 754-1985 (IEEE, Нью-Йорк).

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

Важливо розуміти, що точність не є рівномірною і що це не точне зберігання чисел, як це робиться для цілих чисел.

Приклад :

double a = 0.3 - 0.1;
System.out.println(a);          

відбитки

0.19999999999999998

Якщо вам потрібна довільна точність (наприклад, для фінансових цілей), вам може знадобитися Big Decimal .


7

Звичайна математична відповідь.

Зрозумівши, що число з плаваючою точкою реалізується як деякі біти, що представляють показник ступеня, а решта, більшість із цифр (у двійковій системі), можна мати таку ситуацію:

З великим показником, скажімо, 10²³, якщо міняється найменш значущий біт, з’являється велика різниця між двома сусідніми роздільними мишучими числами. Крім того, десяткова точка бази 2 робить так, що багато чисел 10 базових значень можна лише наблизити; 1/5, 1/10 - нескінченні числа.

Так загалом : числа з плаваючою комою не слід використовувати, якщо ви дбаєте про значні цифри. Для грошових сум із розрахунком, e, a, найкраще використовувати BigDecimal .

Для фізики подвійні числа з плаваючою комою є достатніми, плаваючі майже ніколи. Крім того, частина процесорів із плаваючою комою, FPU, може навіть використовувати трохи більшу точність внутрішньо.


3

Числа з плаваючою комою кодуються за допомогою експоненціальної форми, тобто щось подібне m * b ^ e, тобто зовсім не подібне до цілих чисел. Запитання, яке ви задаєте, було б значущим у контексті фіксованих точок . Доступні численні арифметичні бібліотеки з фіксованою точкою .

Щодо арифметики з плаваючою точкою: Кількість десяткових цифр залежить від подання та системи числення. Наприклад, є періодичні числа ( 0.33333), які не мають скінченного подання у десятковому вигляді, але мають двійкове і навпаки.

Також варто відзначити , що числа з плаваючою точкою до певної точки дійсно є різниця більше , ніж один, тобто value + 1виходи value, так як value + 1не можуть бути закодовані з використанням m * b ^ e, де m, bі eфіксуються в довжину. Те саме відбувається для значень, менших за 1, тобто всі можливі кодові точки не мають однакової відстані.

Через це не існує точності саме nцифр, як у номерах фіксованих точок, оскільки не кожне число з nдесятковими цифрами має кодування IEEE.

Існує майже обов'язковий документ, який ви тоді повинні прочитати, який пояснює числа з плаваючою крапкою: Що кожен знавець інформатики повинен знати про арифметику з плаваючою крапкою .


2
+1 за згадку "Що повинен знати кожен вчений-інформатик про арифметику з плаваючою комою". Однак варто зазначити, що кожне число, яке має скінченне подання двійкового дробу, також має скінченне десяткове подання. Проблема полягає лише в переході від десяткової до двійкової.
Patricia Shanahan

1

Подивіться на Float.intBitsToFloatі Double.longBitsToDouble, який вид пояснює, як біти відповідають числам із плаваючою комою. Зокрема, шматочки нормального floatвиглядають приблизно так

 s * 2^exp * 1.ABCDEFGHIJKLMNOPQRSTUVW

де A ... W - це 23 біти - 0s та 1s - що представляють дріб у двійковому файлі - s дорівнює +/- 1, представлене 0 або 1 відповідно, а exp є 8-бітовим цілим числом із підписом.

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