2014-02-08 18 views
0
float x = 0.98123452f; 
System.out.println(x); //it prints out 0.9812345 

float x = 0.98123453f; 
System.out.println(x); //it prints out 0.98123455 

Я понятия не имею, почему второй результат равен 0.98123455 вместо 0.9812345. Разве точность поплавка не равна 7 десятичным цифрам?java - точность поплавка при выходе в консоль

+2

Не действительно, ни любое другое число десятичных цифр. Он имеет 23 (+1) * бит * точности. Десятичное представление сильно вводит в заблуждение. – harold

+0

Консоль точно не имеет к этому никакого отношения. – EJP

ответ

1

Стандарт IEEE 754 с плавающей точкой представление

0.98123453 

составляет 32 бита (знака, ехр, мантиссы):

0 01111110 11110110011001000110000 

который является:

0.9812345504760742 

с двойной точностью, и отбрасывается в поплавковое десятичное представление:

0.98123455 

Число бит, присвоенных одной точности (поплавок), равно 32 и 64 бит для двойной точности. Обратите внимание, что BigDecimal, который часто предлагается, сохранит ваш номер в виде строки, а не в формате IEEE754. Он будет делать преобразование, когда ему нужно действовать по числу, и, хотя он имеет лучшую точность, он ужасно медленный.

EDIT. Чтобы выяснить, почему он печатает 0.98123455, мы должны заметить, что он является самым близким одинарной точности представление числа 0.98123453:

00111111011110110011001000101111 = 0.9812345 (sp) = 0.9812344908714294 (dp) 
00111111011110110011001000110000 = 0.98123455 (sp) = 0.9812345504760742 (dp) 
00111111011110110011001000110001 = 0.9812346 (sp) = 0.981234610080719 (dp) 

зр = одинарной точности, дп = двойной точности

Перечень является для двоичного диапазона [-1, + 1] вокруг номера, и вы можете видеть, что 0.98123453 ближе всего к суффиксу 10000 мантиссы, а 0.98123452 - ближе всего к суффиксу 01111.

+0

Почему он выводит 8 десятичных цифр вместо 7? – user3143433

+0

Поскольку двойная точность 0,98123452 составляет 0,9812344908 ... которая усекается до 0,9812345 для печати. Таким образом, вы должны задать вопрос наоборот: почему он выводит 7 вместо 8. – mockinterface

0

Нет, float имеет всего шесть цифр десятичной точности.

+0

Я считаю, что в некоторых случаях это может быть более 6 цифр (но не менее 6 во всех случаях). – assylias

+0

6-9, действительно. но шесть - это гарантированное число. – Joey

1

Чтобы увидеть точное значение вашего поплавка, вы можете использовать BigDecimal:

float x = 0.98123452f; 
System.out.println(new BigDecimal(x)); 

, который выводит: 0.981234490871429443359375

Технически, этот поплавок:

float x = 0.981234490871429443359375f; 
System.out.println(new BigDecimal(x)); //prints 0.981234490871429443359375 

имеет 24 (очевидно, была выбрана вишня) ...

Забудьте о том, что выше: BigDecimal имеет только двойной конструктор, поэтому был добавлен двойник, а логика выше ошибочна.

Нижняя строка: не все числа могут быть представлены как поплавок, а промежуток между одним поплавком и следующим изменяется в зависимости от величины числа.

+0

Ну, это потому, что точность BigDecimal не является точностью IEEE-754. Он сохраняет номер в виде строки. – mockinterface

+0

@mockinterface Где я сделал ошибку, так это то, что конструктор не принимает float, поэтому x фактически переводится в double. Однако «* Когда двойной должен использоваться как источник для BigDecimal, обратите внимание, что этот конструктор обеспечивает точное преобразование *», согласно javadoc. – assylias

+0

Несомненно, это просто означает, что он не будет преобразовывать double в строку сначала, чтобы переслать конструктор строк, не позволяя вам больше потерять точность. – mockinterface

1

Не является ли точность поплавка 7 десятичными цифрами?

Номер 23 0двоичный код. Таким образом, минимальное число десятичных цифр, которое может быть представлено в 23 битах, является 6. Это не просто «гарантия», как указано в других ответах здесь, это математическая тавтология, возникающая из log10 (2^23) = 6.92369.

+0

Значимость 32-разрядного двоичного объекта с плавающей запятой IEEE-754 имеет 24 бита, а не 23. 23 закодированы в значении поля, один закодирован через поле экспоненты. –

1

Формат вывода по умолчанию для плавающей запятой в Java - это напечатать достаточно цифры, чтобы преобразование обратно в тип с плавающей точкой давало исходное значение.

Что происходит в деталях в вашем коде:

  • Исходный текст 0.98123452f преобразуется в значение 0.981234490871429443359375 float.
  • Это напечатано как «0.9812345», потому что это всего лишь цифры. Ближайшее значение float до 0,9812345 составляет 0,981234490871429443359375. Однако преобразование «0.981234» в float будет производить 0,981234014034271240234375, поэтому требуется «5».
  • Исходный текст 0.98123453f преобразуется в значение float 0,98123455047607421875.
  • Это напечатано как «0.98123455», потому что это всего лишь цифры.

Интересным следствием этого является то, что, если присвоить значение float к double объекта, а затем напечатать значение double, он будет часто показывать больше цифр, чем печать значение float, даже если значения в точности одна и та же. Поскольку формат double более тонкий (более точный), чем формат float, может быть много значений double между значением, напечатанным для float (например, 0,9812345) и фактическим значением (0,981234490871429443359375). Поэтому для отличия значения требуется больше цифр.

Смежные вопросы