Есть ли способ получить количество мест после десятичной точки в java double? - PullRequest
3 голосов
/ 04 декабря 2009

Я работаю над Java / Groovy программой. У меня есть двойная переменная, которая содержит число, которое было введено пользователем. То, что я действительно хочу знать, это то, сколько цифр пользователь набрал справа от десятичного разряда. Что-то вроде:

double num = 3.14
num.getPlaces() == 2

Конечно, вы не можете сделать это с двойным, так как он использует IEEE с плавающей запятой, и это все приблизительно.

Предполагая, что я не могу получить строку, набранную пользователем, но имею доступ только к двойному значению, в котором сохранено значение, есть ли способ, которым я могу отсканировать это двойное значение с помощью BigDecimal или что-то подобное, чтобы получить "реальное число десятичных знаков? (Когда двойник отображается на экране, он понимает это правильно, поэтому я предполагаю, что есть способ, по крайней мере, хорошо угадать?)

Ответы [ 7 ]

14 голосов
/ 04 декабря 2009

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

«Реальное» число почти наверняка будет иметь больше десятичных разрядов, чем набрал пользователь. Например, 3.14 хранится как точно 3.140000000000000124344978758017532527446746826171875. Я не думаю, что вы хотите отобразить , что для пользователя.

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

3.14
3.140
3.140000
3.14000000000000012434

Все эти четыре строки дадут вам одно и то же значение - из чего следует, что вы не можете возможно вернуться к тому, что набрал пользователь.

Если при все возможно, измените код синтаксического анализа и используйте BigDecimal во всем.

3 голосов
/ 04 декабря 2009

Вы правы, что с двойниками происходит что-то странное, то, что выводится на печать, не совпадает с содержимым переменной.

например:

groovy:000> "123.0001".toBigDecimal()
===> 123.0001
groovy:000> "123.0001".toDouble()
===> 123.0001
groovy:000> new BigDecimal("123.0001".toDouble())
===> 123.000100000000003319655661471188068389892578125

Обратите внимание, что урон наносится при преобразовании строки в double, а не при передаче double в BigDecimal. Подача двойного в BigDecimal просто обеспечивает простой способ увидеть, что на самом деле в двойном, потому что toString обманывает вас.

Как отмечает Джон Скит, точность здесь не вариант. Однако, предполагая, что значение, напечатанное на экране, является результатом вызова toString для double, вы должны иметь возможность получить bigDecimal, который не более ошибочен, чем версия toString для double, например, так:

groovy:000> d = "123.0001".toDouble()
===> 123.0001
groovy:000> d.toString()
===> 123.0001
groovy:000> new BigDecimal(d.toString())
===> 123.0001

Так что вам не нужно привлекать BigDecimal, на самом деле, вы можете просто сделать что-то вроде

groovy:000> d = 123.0001
===> 123.0001
groovy:000> s = d.toString()
===> 123.0001
groovy:000> s.substring(s.indexOf('.')).length() - 1
===> 4

Извините, что отредактировал ваш комментарий, отредактировав.

Кстати, здесь есть что-то близкое к ответу Стива, переведенному на отличный. (Я снял тест на десятичную точку, не найденную, потому что, если вы запустите это на машине с ошибочными локалями, поэтому для десятичной точки не используется точка, я предпочел бы ее взорвать, чем вернуть 0)

def getPlaces(d) {
    s = d.toString()
    s.substring(s.indexOf(".")).length() - 1
}
2 голосов
/ 08 декабря 2009

Да, вы можете. По крайней мере, если вы не возражаете, что иногда вы получаете неправильный результат. Мы должны предположить, что пользователь ленив и ввел не более ~ 12 значащих десятичных цифр.

Затем выполните следующее:

  • Создать BigDecimal с указанным двойным в конструкторе. Это преобразует двойное число в точное десятичное представление.

  • Получить только дробь.

  • Получите BigDecimal.toString () и найдите три или более последовательных цифр «0» или «9».

  • Отрезать дробь после этих трех цифр. Если цифры девять, добавьте «1» в конец. После этого удалите все конечные нули.

  • Подсчитать оставшиеся дробные цифры

Предупреждение: это может быть немного медленно.

Если вам нужно только количество значащих битов в двойнике, вы можете получить их намного быстрее и проще, но, к сожалению, десятичное-> двоичное преобразование использует почти все биты.

1 голос
/ 04 декабря 2009

Если вам абсолютно необходимо взять дубль, и вы не возражаете против использования небольшого вспомогательного метода для его запуска, вы можете написать что-то вроде этого. Вы сказали, что не имеете доступа к значению String того, что ввел пользователь, но есть ли причина, по которой вы не можете преобразовать его в строку и сделать что-то подобное?

static int getPlaces(double num) {
    String numString = String.valueOf(num);

    return numString.indexOf(".0")==numString.length()-2?0:numString.length()-numString.indexOf(".")-1;
}

тогда вместо вашего примера

 num.getPlaces() == 2

Вы можете сделать

 getplaces(num) == 2

Надеюсь, это поможет ..

Обновление, учитывая ваш комментарий That the user entered. Good point.

Если пользователь ввел то, что выглядит как целое число (скажем, 5) без десятичной точки, и вы получаете его как двойное число, то вы получите нечто иное, чем введенное пользователем - он / она введет 5, но вы получите 5,0. Вы не сможете определить, действительно ли пользователь ввел 5 или 5,0.

0 голосов
/ 29 января 2012

Конвертировать в BigDecimal. BigDecimal.scale () = количество мест

0 голосов
/ 04 декабря 2009

, поэтому, если это введенное пользователем значение. Примите значение в виде строки. Затем вы можете использовать строковые функции, чтобы найти положение "." и затем вычтите это число из длины строки, чтобы получить число, которое вы ищете. Конечно, вы захотите его урезать () и убедиться, что это на самом деле введенное число.

0 голосов
/ 04 декабря 2009

если вы застряли с двойным, преобразовать в строку и подсчитать количество символов после десятичной точки. Я думаю, что есть какая-то магия, которая отображает числа вроде 1.99999999998 как "2"

...