Отображаемая точность Java с плавающей точкой - PullRequest
0 голосов
/ 25 февраля 2019

Если мы запустим следующий код:

float f = 1.2345678990922222f;
double d = 1.22222222222222222222d;
System.out.println("f = " + f + "\t" + "d = " + d);

, то он напечатает:

f = 1.2345679   d = 1.2222222222222223

Длинный хвост в литерале 1.2345678990922222 игнорируется, но длинный хвост в 1.22222222222222222222 не является (последняя десятичная цифра в переменной d становится 3 вместо 2).Почему?

1 Ответ

0 голосов
/ 25 февраля 2019

Количество цифр, которое вы видите при печати float или double, является следствием правил Java для преобразования по умолчанию float и double в десятичное число.

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

В вашем примере 1.2345678990922222f в исходном тексте преобразуется в float значение 1.2345678806304931640625, поскольку из всех значений, представленных в типе float, это значение наиболее близко к 1.2345678990922222.Следующие более низкие и следующие более высокие значения - это 1,23456776142120361328125 и 1,23456799983978271484375.

При печати этого значения Java нужно вывести только «1,2345679», потому что этого достаточно, чтобы мы могли выбрать значение float 1,2345678806304931640625 у его соседей1.23456776142120361328125 и 1.23456799983978271484375.

Для вашего double примера, 1.22222222222222222222d преобразуется в 1.22222222222222232090871330001391470432281494140625.Следующие более низкие и следующие более высокие значения, представленные в double, представляют собой 1,2222222222222220988641083749826066195964813232421875 и 1,2222222222222225429533182250452227890491485595703125.Как вы можете видеть, чтобы отличать 1.22222222222222232090871330001391470432281494140625 от соседей, Java необходимо вывести «1.2222222222222223».

Сноска

1 Правило Java SE 10 можно найти в документации по java.lang.float, в разделе toString(float d).Документация double аналогична.Отрывок с наиболее релевантной частью, выделенной жирным шрифтом, выглядит так:

Возвращает строковое представление float argument.Все упомянутые ниже символы являются символами ASCII.

  • Если аргумент равен NaN, результатом является строка "NaN".

  • В противном случаеРезультатом является строка, которая представляет знак и величину (абсолютное значение) аргумента.Если знак отрицательный, первым символом результата будет '-' ('\u002D');если знак положительный, знак не появляется в результате.Что касается величины м :

    • Если м - бесконечность, то она представлена ​​символами «Бесконечность»;таким образом, положительная бесконечность дает результат «Бесконечность», а отрицательная бесконечность - «-Infinity».

    • Если m равно нулю, то оно представлено символами"0.0";таким образом, отрицательный ноль дает результат "-0.0", а положительный ноль дает результат "0.0".

    • Если m больше или равно 10 -3 , но меньше 10 7 , тогда он представляется как целая часть m , в десятичной форме без начальных нулей, за которыми следует '.'('\u002E'), за которым следуют одна или несколько десятичных цифр, представляющих дробную часть m .

    • Если m меньше 10 -3 или больше или равно 10 7 , тогда оно представлено в так называемой "компьютеризированной научной нотации".Пусть n будет уникальным целым числом таким, что 10 n m <10 <sup> n + 1;тогда пусть a будет математически точным отношением m и 10 n , так что 1 ≤ a <10Затем величина представляется как целая часть <em>a , как одна десятичная цифра, за которой следует '.' ('\u002E'), за которой следуют десятичные цифры, представляющие дробную часть a , за которым следует буква 'E' ('\u0045'), за которой следует представление n в виде десятичного целого числа, полученного методом Integer.toString(int).

Сколькоцифры должны быть напечатаны для дробной части m или a ? Должна быть хотя бы одна цифра для представления дробной части, и помимо этого столько, но только столько, сколько цифр необходимо для уникального различия значения аргумента от смежных значений типа float. То есть предположим, что x является точным математическим значением, представленным десятичным представлением, полученным этим методом для конечного ненулевого аргумента f .Тогда f должно быть значением float, ближайшим к x ;или, если два значения float одинаково близки к x , тогда f должно быть одним из них, а младший значащий бит из значения f долженбыть 0.

...