Double.toString всегда производит то же самое, что и двойной литерал? - PullRequest
0 голосов
/ 12 июля 2020

Double.toString(0.1) дает «0,1», но 0,1 - это число с плавающей запятой.

Число с плавающей запятой не может точно представлять на языке программы, но Double.toString дает точный результат (0,1), как делает это, всегда ли он дает результат, который математически равен двойной литерал ?

Предположим, что литерал имеет двойную точность.

Вот проблема Я вижу:

При использовании Apache POI для чтения файла Excel XSSFCell.getNumericCellValue может возвращать только double, если я использую BigDecimal.valueOf для преобразования его в BigDecimal, это всегда безопасно, а почему?

Ответы [ 4 ]

3 голосов
/ 12 июля 2020

Double.toString дает точный результат (0,1), как он это делает, всегда ли он дает результат, математически равный двойному литералу ?

Double.toString(XXX) всегда будет давать число, равное XXX, если XXX является десятичным числом с 15 или менее значащими цифрами и находится в диапазоне формата Double.

Есть для этого есть две причины:

  1. Формат Double (IEEE-754 binary64) имеет достаточную точность, чтобы всегда можно было различить десятичные числа 15-di git.
  2. Double.toString не отображает точное значение Double, а вместо этого производит наименьшее количество значащих цифр, необходимых для отличия guish числа от ближайших Double значений.

Например, литерал 0.1 в исходном тексте преобразуется в значение Double 0.1000000000000000055511151231257827021181583404541015625. Но Double.toString по умолчанию не выдаст все эти цифры. Используемый алгоритм дает «0,1», потому что этого достаточно, чтобы однозначно отличить guish 0,1000000000000000055511151231257827021181583404541015625 от двух его соседей, которые равны 0,099999999999999167332731531132594682276248931884765625 и 0,128000000000000295 Оба они дальше от 0,1.

Таким образом, Double.toString(1.234), Double.toString(123.4e-2) и Double.toString(.0001234e4) все будут давать «1,234» - число, значение которого равно всем исходным десятичным числам (прежде чем они будут преобразован в Double), хотя по форме он отличается от некоторых из них.

При использовании Apache POI для чтения файла Excel XSSFCell.getNumericCellValue может возвращать только double, если я использую BigDecimal.valueOf, чтобы преобразовать его в BigDecimal, всегда ли это безопасно и почему?

Если извлекаемое значение ячейки не может быть представлено как Double, тогда XSSFCell.getNumericCellValue должен его изменить. . По памяти я думаю, что BigDecimal.valueOf даст точное значение возвращенного Double, но я не могу авторитетно говорить об этом. Это отдельный вопрос от того, как ведут себя Double и Double.toString, поэтому вы можете задать его как отдельный вопрос.

2 голосов
/ 12 июля 2020

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

Например:

System.out.println (Double.toString(0.123456789123456789))

отпечатки

0.12345678912345678
2 голосов
/ 12 июля 2020

10e-5d - двойной буквальный эквивалент 10 ^ -5 Double.toString(10e-5d) возвращает "1.0E-4"

0 голосов
/ 13 июля 2020

Я согласен с Эри c Ответ Постпишила , но может помочь другое объяснение.

Для каждого двойного числа есть диапазон действительных чисел, которые округляются до половины -семь правил. Для 0,1000000000000000055511151231257827021181583404541015625, результат округления 0,1 до двойного значения, диапазон равен [0,099999999999999998612221219218554324470460414886474609375,0.10000000000000001249000902703301107976585615, что число * 0,19 * любое число *, что * любое число * arith27031076585626 равно

Double.toString(x) возвращает строковое представление действительного числа в диапазоне, который преобразуется в x и имеет наименьшее количество десятичных знаков. Выбор любого действительного числа в этом диапазоне гарантирует, что при двустороннем преобразовании числа типа double в String с помощью Double.toString и последующем преобразовании String обратно в число double с использованием правил округления и половинной четности будет восстановлено исходное значение.

System.out.println(0.100000000000000005); выводит «0,1», потому что 0,100000000000000005 находится в диапазоне, который округляется до того же числа, что и 0,1, а 0,1 - действительное число в этом диапазоне с наименьшим количеством десятичных знаков. чем "0,1" с действительным числовым значением в диапазоне редки. Это более заметно для float из-за меньшей точности. System.out.println(0.100000001f); печатает «0,1».

...