Кто-нибудь знает, как я могу округлить двойное значение до 3 значащих цифр, как примеры на этом сайте
Раунд от двух до трех значащих цифр
Ответ 1
double d = ...;
BigDecimal bd = new BigDecimal(d);
bd = bd.round(new MathContext(3));
double rounded = bd.doubleValue();
Ответ 2
public String toSignificantFiguresString(BigDecimal bd, int significantFigures ){
String test = String.format("%."+significantFigures+"G", bd);
if (test.contains("E+")){
test = String.format(Locale.US, "%.0f", Double.valueOf(String.format("%."+significantFigures+"G", bd)));
}
return test;
}
Ответ 3
Если вы хотите сделать это вручную:
import java.lang.Math;
public class SigDig {
public static void main(String[] args) {
System.out.println(" -123.456 rounded up to 2 sig figures is " + sigDigRounder(-123.456, 2, 1));
System.out.println(" -0.03394 rounded down to 3 sig figures is " + sigDigRounder(-0.03394, 3, -1));
System.out.println(" 474 rounded up to 2 sig figures is " + sigDigRounder(474, 2, 1));
System.out.println("3004001 rounded down to 4 sig figures is " + sigDigRounder(3004001, 4, -1));
}
public static double sigDigRounder(double value, int nSigDig, int dir) {
double intermediate = value/Math.pow(10,Math.floor(Math.log10(Math.abs(value)))-(nSigDig-1));
if(dir > 0) intermediate = Math.ceil(intermediate);
else if (dir< 0) intermediate = Math.floor(intermediate);
else intermediate = Math.round(intermediate);
double result = intermediate * Math.pow(10,Math.floor(Math.log10(Math.abs(value)))-(nSigDig-1));
return(result);
}
}
Вышеупомянутый метод округляет двойное до требуемого числа значимых цифр, обрабатывает отрицательные числа и может быть явно указано округление вверх или вниз
Ответ 4
Нет ничего плохого в ответе Шона Оуэна (fooobar.com/questions/24400/...). Однако, в зависимости от вашего варианта использования, вы можете захотеть получить строковое представление. В этом случае, IMO лучше всего конвертировать, находясь в пространстве BigDecimal, используя:
bd.toPlainString();
... если это ваш вариант использования, то вы можете быть разочарованы тем, что код, адаптированный из ответа Оуэна, выдаст следующее:
d = 0.99, significantDigits = 3 ==> 0.99
... вместо строго более точного 0.990
.
Если такие вещи важны в вашем случае использования, тогда я предлагаю следующую адаптацию к ответу Оуэна; очевидно, вы также можете вернуть сам BigDecimal вместо вызова toPlainString()
&— Я просто предоставил это для полноты.
public static String setSignificanDigits(double value, int significantDigits) {
if (significantDigits < 0) throw new IllegalArgumentException();
// this is more precise than simply doing "new BigDecimal(value);"
BigDecimal bd = new BigDecimal(value, MathContext.DECIMAL64);
bd = bd.round(new MathContext(significantDigits, RoundingMode.HALF_UP));
final int precision = bd.precision();
if (precision < significantDigits)
bd = bd.setScale(bd.scale() + (significantDigits-precision));
return bd.toPlainString();
}
Ответ 5
как я могу округлить двойное значение до 3 значимых цифр
Вы не можете. Двойки представляются в двоичном формате. У них нет десятичных знаков для округления. Единственный способ получить определенное число десятичных знаков - преобразовать его в десятичный радикс и оставить его там. В тот момент, когда вы преобразуете его обратно в двойное, вы снова потеряли десятичную точность.
Для всех поклонников, здесь и в другом месте, для преобразования в другие радики и обратно, или умножения и деления на десятичные числа, пожалуйста, отобразите полученное двойное значение% 0,001 или то, что требует требуемая точность, и объясните результат.
EDIT: В частности, сторонники этих методов должны объяснить 92% частоту отказа следующего кода:
public class RoundingCounterExample
{
static float roundOff(float x, int position)
{
float a = x;
double temp = Math.pow(10.0, position);
a *= temp;
a = Math.round(a);
return (a / (float)temp);
}
public static void main(String[] args)
{
float a = roundOff(0.0009434f,3);
System.out.println("a="+a+" (a % .0001)="+(a % 0.001));
int count = 0, errors = 0;
for (double x = 0.0; x < 1; x += 0.0001)
{
count++;
double d = x;
int scale = 2;
double factor = Math.pow(10, scale);
d = Math.round(d * factor) / factor;
if ((d % 0.01) != 0.0)
{
System.out.println(d + " " + (d % 0.01));
errors++;
}
}
System.out.println(count + " trials " + errors + " errors");
}
}
Ответ 6
Я обычно не оборачиваю сам номер, а округляю строковое представление числа, когда мне нужно его отображать, потому что обычно это отображение, которое имеет значение, которое требует округления (хотя это может быть неверно в ситуациях и, возможно, но вам нужно уточнить это, если это так). Таким образом, мой номер сохраняет свою точность, но его отображение упрощается и упрощается для чтения. Для этого можно использовать объект DecimalFormat, например, инициализированный строкой "0.000" (new DecimalFormat("0.000")
) или использовать String.format("%.3f", myDouble)
или несколько других способов.
Например:
// yeah, I know this is just Math.PI.
double myDouble = 3.141592653589793;
DecimalFormat myFormat = new DecimalFormat("0.000");
String myDoubleString = myFormat.format(myDouble);
System.out.println("My number is: " + myDoubleString);
// or you can use printf which works like String.format:
System.out.printf("My number is: %.3f%n", myDouble);