Я не хочу ограничивать количество значащих цифр в BigDecimal. Я только хочу найти количество значащих цифр, которые имеет это число.
Есть ли способ сделать это без преобразования числа в строку и подсчета числовых символов?
Я не хочу ограничивать количество значащих цифр в BigDecimal. Я только хочу найти количество значащих цифр, которые имеет это число.
Есть ли способ сделать это без преобразования числа в строку и подсчета числовых символов?
Я полагаю, вам нужна комбинация stripTrailingZeros, precision и scale< /a>, как показано здесь:
import java.math.*;
public class Test {
public static void main(String[] args) {
test("5000"); // 4
test("5000.00"); // 4
test("5000.12"); // 6
test("35000"); // 5
test("35000.00"); // 5
test("35000.12"); // 7
test("35000.120"); // 7
test("0.0034"); // 2
test("1.0034"); // 5
test("1.00340"); // 5
}
private static void test(String input) {
System.out.println(input + " => " +
significantDigits(new BigDecimal(input)));
}
private static int significantDigits(BigDecimal input) {
input = input.stripTrailingZeros();
return input.scale() < 0
? input.precision() - input.scale()
: input.precision();
}
}
Вызов stripTrailingZeros обязателен, так как в противном случае вполне возможно, что BigDecimal будет храниться в "ненормализованной" форме. Например, new BigDecimal(5000) имеет точность 4, а не 1.
Вызов scale() используется для обработки случаев, когда нормализованная форма имеет конечные нули перед десятичной запятой, но ничего после десятичной точки. В этом случае шкала всегда будет отрицательной и указывает количество завершающих нулей.
РЕДАКТИРОВАТЬ: Случаи с конечными нулями, но без десятичной точки, по своей сути неоднозначны - например, нет определенного количества значащих цифр до «5000». В приведенном выше коде все конечные нули перед десятичной точкой рассматриваются как значимые.
precision() сам по себе не является ответом, но new BigDecimal(8.6).precision() каким-то образом возвращает 50, а new BigDecimal(8.6).stripTrailingZeroes().precision() также возвращает 50.
- person rgettman; 30.01.2014
new BigDecimal(8.6) на самом деле не 8,6 ... это точное значение ближайшего double к 8.6. Если вы ожидали получить 2, вы должны использовать new BigDecimal("8.6"). Просто распечатайте new BigDecimal(8.6), и вы поймете, что я имею в виду.
- person Jon Skeet; 30.01.2014
new BigDecimal("5000.0").stripTrailingZeros().precision() возвращает 1, но в соответствии с принятыми определениями вы хотите, чтобы он возвращал 5 (поскольку вы не добавили бы .0 в конец числа, если бы оно не было значительным). Кроме того, количество значащих цифр в "5000" в любом случае неоднозначно. См. Значимые цифры в Википедии.
- person ajb; 30.01.2014
BigDecimal нет t способен различать, скажем, 5000 с одной значащей цифрой и 5000 с двумя, например.)
- person ajb; 30.01.2014
Следующая модификация ответа Джона возвращает результаты, которые мне кажутся правильными:
private static int significantDigits(BigDecimal input) {
return input.scale() <= 0
? input.precision() + input.stripTrailingZeros().scale()
: input.precision();
}
(Обратите внимание, что input.stripTrailingZeros().scale() в этих тестах всегда оказывается отрицательным.)
Кроме того, как я отметил выше, BigDecimal не может отличить, скажем, "5000" с одной значащей цифрой от "5000" с двумя, например. Кроме того, согласно определениям, «5000». (с завершающей запятой) должно иметь ровно четыре значащих цифры, но BigDecimal не может с этим справиться. (см. http://en.wikipedia.org/wiki/Significant_figures определения с использованием.)
Ответ Джона правильный в большинстве случаев, кроме экспоненциального числа:
private static int significantDigits(BigDecimal input) {
return input.scale() <= 0
? input.precision() + input.stripTrailingZeros().scale()
: input.precision();
}
скажем, ввод как 1.230000E17, функция возвращает 18, однако правильные значащие цифры должны быть 7.