#java #android #double #numeric #bigdecimal
#java #округление
Вопрос:
Есть ли какая-либо встроенная функция в java, чтобы сообщить мне, сколько знаков после запятой в double. Например:
101.13 = 2
101.130 = 3
1.100 = 3
1.1 = 1
-3.2322 = 4 etc.
Я рад сначала преобразовать в другой тип, если это необходимо, я сначала рассматривал преобразование в bigdecimal, но безуспешно.
Ответ №1:
Вы могли бы использовать BigDecimal.scale(), если вы передаете число в виде строки, подобной этой:
BigDecimal a = new BigDecimal("1.31");
System.out.println(a.scale()); //prints 2
BigDecimal b = new BigDecimal("1.310");
System.out.println(b.scale()); //prints 3
но если у вас уже есть число в виде строки, вы могли бы также просто проанализировать строку с регулярным выражением, чтобы увидеть, сколько в ней цифр:
String[] s = "1.31".split("\.");
System.out.println(s[s.length - 1].length());
Преимущество использования BigDecimal может заключаться в том, что оно проверяет, действительно ли строка является числом; используя метод string, вы должны сделать это самостоятельно. Кроме того, если у вас есть числа как double, вы не можете различать между 1.31
и 1.310
(они точно такие же двойные), как указывали и другие.
Ответ №2:
Нет.
1.100 и 1.1 — это в точности одно и то же значение (они представлены точно так же побитово в double
).
Поэтому вы никогда не сможете получить такого рода информацию из double
.
Единственное, что вы можете сделать, это получить минимальное количество десятичных цифр, необходимое для преобразования десятичного числа в одно и то же double
значение. И это так же просто, как вызвать Double.toString()
и проверить, сколько там десятичных разрядов.
Комментарии:
1. Вызов toString() кажется немного шатким, но это была моя первоначальная мысль.
2.@Karl: это шатко, но, возможно, лучшее, что вы можете сделать. Оно разбивается на очень большие и очень маленькие значения (как вы получите научную нотацию). Единственное 100% правильное решение — выполнить этот тест, когда у вас есть значение в виде
String
прежде, чем вы преобразуете его вdouble
(как демонстрирует Андрей).
Ответ №3:
Количество знаков после запятой в double равно 16.
64-разрядные числа. 52-битная мантисса. 52 бита — это примерно 16 десятичных разрядов.
Смотрите http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html .
double, значения которого включают 64-разрядные числа с плавающей запятой IEEE 754.
Комментарии:
1. Нет, это количество десятичных цифр , и это неправильно, оно равно 15,9. Рассмотрим «123456789012345». Пятнадцать десятичных разрядов, ноль десятичных знаков. «12345678901234.5». Пятнадцать десятичных цифр, один десятичный знак. И т.д.
2. @EJP: Я бы подумал, что 15,9 — это «Около 16». Из вашего комментария следует, что вы не думаете, что 15,9 — это «около 16». Если вы хотите утверждать, что 15,9 — это не «около 16», то вы также ошибаетесь, поскольку это тоже не 15,9. В Википедии написано «17 десятичных разрядов» и 15,955 цифр.
3. @EJP: Пожалуйста, внимательно прочитайте стандарт IEEE. В частности, прочитайте о неявных битах в значимом.
4. Хорошо, мы просто придираемся здесь, но это 15.9545897701910000. До 16 знаков после запятой 😉
5. @EJP: Нет. Мы не придираемся. Ваш первоначальный комментарий был ясен. «около 16 неверно». И затем вы утверждали, что это было 15,9, что в равной степени неверно. Не похоже, что вы придираетесь. Похоже, вы хотите сказать что-то важное, и вы повторили это что-то важное уже четыре разных раза. Это не придирки. Вам нужно добавить к этому ответу кое-что важное . Что-то насчет того, что 16 даже близко не соответствует 15,955.
Ответ №4:
Нет, нет встроенной функции, о которой я знаю.
Однако есть простой способ сделать это. Двойное.toString выдаст вам строку, содержащую ВСЕ значащие десятичные цифры в double. Ниже приведены некоторые свойства этой строки:
- Результирующая строка может быть в десятичной или научной нотации, в зависимости от значения double.
- Удвоения, которые преобразуются в десятичные дроби 10 000 000 или больше или меньше 1/1000, приводят к научным обозначениям. В противном случае они представлены в десятичной системе счисления.
Использование Double.Строка для определения количества знаков после запятой, по сути, включает в себя количество значащих цифр справа от десятичной точки минус показатель научной записи, если таковой имеется. В десятичной системе счисления всегда будет по крайней мере одна цифра справа от десятичной точки и по крайней мере одна цифра слева от десятичной точки, даже если это ноль. Поскольку нас интересуют десятичные разряды для значащих цифр, завершающий ноль справа от десятичной точки вызывает беспокойство и не должен учитываться как десятичный знак.
Следующий код сделает для вас хороший расчет:
StringBuffer stringBuffer = new StringBuffer(Double.toString(1234.567890D));
System.out.println(stringBuffer.toString());
int i; // general purpose character index
int exponent;
int decimalPlaces;
if ((i = stringBuffer.indexOf("E")) > -1) { // scientific notation...
// turn scientific notation exponent into an integer
exponent = Integer.parseInt(stringBuffer.substring(i 1));
// truncate the exponent from the StringBuffer
stringBuffer = stringBuffer.delete(i, stringBuffer.length());
} else { // decimal notation, could be trailing zero
exponent = 0; // no exponent, so zero
// point i to trailing zero and truncate it, if there is one
if (stringBuffer.charAt((i = stringBuffer.length() - 1)) == '0') {
stringBuffer = stringBuffer.deleteCharAt(i); // delete trailing zero
}
}
// stringBuffer now contains only significant digits to the
// right of the decimal point, if there are any
decimalPlaces = stringBuffer.length() - 1 - stringBuffer.indexOf(".") - exponent;
// zero or positive number is decimal places
// negative number is number of zeroes to the left of the decimal point
// between the decimal point and the least significant digit
System.out.println(decimalPlaces);
У меня есть несколько вопросов по поводу поставленного вопроса. Какого рода точность ожидается при десятичном представлении double? Используются ли двойные значения для ненадлежащего выполнения десятичных вычислений? Десятичные вычисления с десятичными дробями с использованием чисел с плавающей запятой и двойных чисел могут иметь результаты, которые неожиданно содержат 16 или 17 значащих цифр и могут быть лишь приближениями к ожидаемым результатам эквивалентных десятичных вычислений.
Один из аспектов float, doubles, long doubles (он же quads), который, кажется, ставит в тупик программистов и дизайнеров, заключается в том, что все эти форматы фактически хранятся в виде двоичных дробных чисел, которые могут только приближаться к десятичным числам, за исключением очень, очень немногих чисел, большинство из которых довольно близко к значениям 1, -1 плюс нулевое значение. По мере продвижения к положительной бесконечности или нулю от 1, или к отрицательной бесконечности или нулю от -1, разреженность приближения станет очевидной.
Почти все десятичные дроби не имеют прямого представления в виде чисел с плавающей запятой и удвоений. Точное представление имеют только десятичные дроби, которые могут быть составлены из суммы некоторой комбинации следующих рядов дробей:
1, 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128, 1/256, …, 1/4503599627370496
Все остальное — приближения.
Целые числа, большие, чем 9007199254740992 или меньше, чем -9007199254740992, могут не иметь точного представления, и разреженность увеличивается экспоненциально, поскольку целые числа увеличиваются выше положительных или уменьшаются ниже отрицательных значений соответственно.
Другой способ взглянуть на это — понять, что 64-разрядный стандарт IEEE удваивает нормализованные приблизительные положительные и отрицательные десятичные числа, имеющие абсолютные значения в диапазоне от 2.2250783858507201400 E -308 до 1.797693134862315700 E 308. Однако для этих приближений доступны только значения 1.8446744073709551616 E 19. Это означает, что около 1.0 E 607 десятичных значений имеют общее представление с некоторыми другими десятичными значениями, которые более точно аппроксимируются значением double.
Поведение float и doubles разрушает десятичные вычисления, требующие точной десятичной точности, такие как финансовые расчеты, и именно поэтому, если не приемлемо высокоточное приближение, следует использовать масштабированные целые числа и длины или такие классы, как BigInteger и BigDecimal, для вычислений, требующих точной десятичной точности, округления и прецизионности.
Ответ №5:
// ****************************************************************
public int getDecimals(double doubleValue) {
// ****************************************************************
BigDecimal bd1 = new BigDecimal(Double.toString(doubleValue)).stripTrailingZeros();
return bd1.scale();
}
Комментарии:
1. Часть toString имеет решающее значение.
Ответ №6:
Из того, что было много лет назад, я вспоминаю ответ из 16 цифр, всего до и после десятичной точки.
Я написал крошечный фрагмент кода, чтобы проверить это.
public class test {
public static void main(String[] args) {
double x;`enter code here`
x = 3411.999999999999;
System.out.println("16: " x); // gives 3411.999999999999
x = 3411.9999999999999;
System.out.println("17: " x); // gives 3412.0
x = 0.9999999999999999;
System.out.println("16: " x); // gives 0.9999999999999999
x = 0.99999999999999999;
System.out.println("17: " x); // gives 1.0
}
}
Там 4 12 = 16 цифр. Запуск выдает 3411.999999999999.
Теперь добавьте еще одну 9 после десятичной точки, чтобы в общей сложности получилось 17 — 3411,9999999999999 — и запустите заново. Выведенное значение равно 3412.0. В этом случае мы перегружаем внутреннее представление x, и число округляется внутренне для сохранения.
Println точно печатает то, что он видит внутри. Для хранения двойного числа с плавающей запятой (значение и экспонента — см. IEEE 754 для получения подробных сведений) требуется ровно столько битов — 64, если быть точным.
Поиграйте со значением x, и вы увидите эффекты. Например, 0,999999999999999999 (16 секунд 9) дает результат 0,99999999999999999999; 0,99999999999999999 (17 секунд 9) дает 1,0.
Надеюсь, это поможет.
Ответ №7:
StringBuffer stringBuffer = new StringBuffer(Double.toString(ratioGrossYield));
int i; // general purpose character index
int exponent;
int decimalPlaces;
if ((i = stringBuffer.indexOf("E")) > -1) { // scientific notation...
// turn scientific notation exponent into an integer
exponent = Integer.parseInt(stringBuffer.substring(i 1));
// truncate the exponent from the StringBuffer
stringBuffer = stringBuffer.delete(i, stringBuffer.length());
} else { // decimal notation, could be trailing zero
exponent = 0; // no exponent, so zero
// point i to trailing zero and truncate it, if there is one
if (stringBuffer.charAt((i = stringBuffer.length() - 1)) == '0') {
stringBuffer = stringBuffer.deleteCharAt(i); // delete trailing zero
}
}
// stringBuffer now contains only significant digits to the
// right of the decimal point, if there are any
decimalPlaces = stringBuffer.length() - 1 - stringBuffer.indexOf(".") - exponent;
// zero or positive number is decimal places
// negative number is number of zeroes to the left of the decimal point
// between the decimal point and the least significant digit
if (stringBuffer.charAt(stringBuffer.length() - 1) == '0') {
return decimalPlaces-1;
} else {
return decimalPlaces;
}