在Java中如何将数字四舍五入到小数点后n位

在Java中如何将数字四舍五入到小数点后n位,java,decimal,rounding,digits,Java,Decimal,Rounding,Digits,我想要的是一种将double转换为字符串的方法,该方法使用向上舍入法进行四舍五入-即,如果要舍入的小数点为5,它总是向上舍入到下一个数字。这是大多数人在大多数情况下期望的标准四舍五入方法 我还希望只显示有效数字,即不应有任何尾随零 我知道这样做的一种方法是使用String.format方法: String.format("%.5g%n", 0.912385); 返回: 0.91239 0.91230 0.91238 这很好,但是它总是显示带有5位小数的数字,即使它们不重要: String

我想要的是一种将double转换为字符串的方法,该方法使用向上舍入法进行四舍五入-即,如果要舍入的小数点为5,它总是向上舍入到下一个数字。这是大多数人在大多数情况下期望的标准四舍五入方法

我还希望只显示有效数字,即不应有任何尾随零

我知道这样做的一种方法是使用
String.format
方法:

String.format("%.5g%n", 0.912385);
返回:

0.91239
0.91230
0.91238
这很好,但是它总是显示带有5位小数的数字,即使它们不重要:

String.format("%.5g%n", 0.912300);
返回:

0.91239
0.91230
0.91238
另一种方法是使用
DecimalFormatter

DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
返回:

0.91239
0.91230
0.91238
但是,正如您所看到的,这使用了半偶数舍入。也就是说,如果前一个数字是偶数,它将向下取整。我想要的是:

0.912385 -> 0.91239
0.912300 -> 0.9123

在Java中实现这一点的最佳方法是什么?

假设
双精度
,您可以执行以下操作:

(double)Math.round(value * 100000d) / 100000d
这是5位数的精度。零的数量表示小数的数量。

使用,显式设置以处理半偶数轮的问题,然后使用所需输出的格式模式

double myNum = .912385;
int precision = 10000; //keep 4 digits
myNum= Math.floor(myNum * precision +.5)/precision;
例如:

DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.CEILING);
for (Number n : Arrays.asList(12, 123.12345, 0.23, 0.1, 2341234.212431324)) {
    Double d = n.doubleValue();
    System.out.println(df.format(d));
}
给出输出:

12
123.1235
0.23
0.1
2341234.2125

编辑:原始答案不涉及双值的准确性。如果你不太在乎它是向上还是向下,那就好了。但是如果您想要精确的舍入,那么您需要考虑值的预期精度。浮点值在内部具有二进制表示形式。这意味着像2.7735这样的值实际上在内部并没有精确的值。它可以稍大或稍小。如果内部值稍小,则不会四舍五入到2.7740。要纠正这种情况,您需要了解正在使用的值的准确性,并在四舍五入之前加上或减去该值。例如,当您知道您的值精确到6位时,若要将中间值向上舍入,请将该精度添加到值中:

Double d = n.doubleValue() + 1e-6;
要向下取整,请减去精度

您也可以使用

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
以确保具有尾随的0

new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);
将为您获取一个
BigDecimal
。要从中提取字符串,只需调用
BigDecimal
toString
方法,或者为Java 5+调用
toPlainString
方法即可获得纯格式字符串

示例程序:

package trials;
import java.math.BigDecimal;

public class Trials {

    public static void main(String[] args) {
        int yourScale = 10;
        System.out.println(BigDecimal.valueOf(0.42344534534553453453-0.42324534524553453453).setScale(yourScale, BigDecimal.ROUND_HALF_UP));
    }
Real的Java如何使用此解决方案,它也与Java1.6之前的版本兼容

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
return bd.doubleValue();
更新:BigDecimal.ROUND\u HALF\u不推荐使用-使用RoundingMode 假设你有

double d = 9232.129394d;
你可以用

或者没有大十进制

d = Math.round(d*100)/100.0d;

对于这两种解决方案,您可以使用以下实用方法-

public static double round(double valueToRound, int numberOfDecimalPlaces)
{
    double multipicationFactor = Math.pow(10, numberOfDecimalPlaces);
    double interestedInZeroDPs = valueToRound * multipicationFactor;
    return Math.round(interestedInZeroDPs) / multipicationFactor;
}

@米尔豪斯:舍入的十进制格式非常好:

您也可以使用

DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
以确保具有尾随的0

new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP);
我想补充一点,这种方法非常适合提供实际的 数字,舍入机制-不仅在视觉上,而且在处理时

假设:您必须在GUI中实现舍入机制 节目。简单更改结果输出的准确性/精度 更改插入符号格式(即括号内)。以便:

DecimalFormat df = new DecimalFormat("#0.######");
df.format(0.912385);
将作为输出返回:
0.912385

DecimalFormat df = new DecimalFormat("#0.#####");
df.format(0.912385);
将作为输出返回:
0.91239

DecimalFormat df = new DecimalFormat("#0.####");
df.format(0.912385);
将作为输出返回:
0.9124

[编辑:如果插入符号格式类似(“#0.##############”)那么您也可以编辑 输入一个十进制数,例如3.1415926,为了参数起见,输入DecimalFormat 不会产生任何垃圾(例如尾随的零),并将返回:
3.1415926
。如果你是那样想的。当然,这有点冗长 对于一些开发人员来说——但是,嘿,它的内存占用很低 在处理过程中,非常容易实现。]

因此,从本质上讲,DecimalFormat的美妙之处在于它同时处理字符串 外观-以及设置的舍入精度级别。因此:你
以一个代码实现的价格获得两个好处。;)

如果您真的希望十进制数用于计算(而不仅仅是用于输出),请不要使用基于二进制的浮点格式,如double

Use BigDecimal or any other decimal-based format.
我确实使用BigDecimal进行计算,但请记住它取决于 你正在处理的数字。在我的大多数实现中,我发现从double或 整型到长型足够进行大量计算

事实上,我已经 最近使用解析为Long以获得准确的表示(与十六进制结果相反) 在一个图形用户界面中,像字符一样大的数字
示例)。

下面的代码片段显示了如何显示n位数字。诀窍是将变量pp设置为1,后跟n个零。在下面的示例中,变量pp值有5个零,因此将显示5位数字

double pp = 10000;

double myVal = 22.268699999999967;
String needVal = "22.2687";

double i = (5.0/pp);

String format = "%10.4f";
String getVal = String.format(format,(Math.round((myVal +i)*pp)/pp)-i).trim();

您可以使用DecimalFormat类

double d = 3.76628729;

DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal =  Double.valueOf(newFormat.format(d));

正如其他一些人所指出的,正确的答案是使用
DecimalFormat
BigDecimal
。浮点没有小数位数,因此您不可能在第一位舍入/截断到特定的小数位数。您必须以十进制基数工作,这就是这两个类所做的

我将下面的代码作为一个反例发布给这个线程中的所有答案,事实上整个StackOverflow(和其他地方)都建议先乘法,然后截断,然后除法。这种技术的拥护者有责任解释为什么以下代码在超过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 % .001)="+(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");
    }
}
编辑:为了解决下面的一些评论,我使用
BigDecimal
newmathcontext(16)
对模运算重新定义了测试循环的模部分,如下所示:

public static void main(String[] args)
{
    int count = 0, errors = 0;
    int scale = 2;
    double factor = Math.pow(10, scale);
    MathContext mc = new MathContext(16, RoundingMode.DOWN);
    for (double x = 0.0; x < 1; x += 0.0001)
    {
        count++;
        double d = x;
        d = Math.round(d * factor) / factor;
        BigDecimal bd = new BigDecimal(d, mc);
        bd = bd.remainder(new BigDecimal("0.01"), mc);
        if (bd.multiply(BigDecimal.valueOf(100)).remainder(BigDecimal.ONE, mc).compareTo(BigDecimal.ZERO) != 0)
        {
            System.out.println(d + " " + bd);
            errors++;
        }
    }
    System.out.println(count + " trials " + errors + " errors");
}

试试这个:org.apache.commons.math3.util.Precision.round(双x,整数刻度)

见:

亚太地区
double rounded = Precision.round(0.912385, 5, BigDecimal.ROUND_HALF_UP);
double rounded = Functions.round(0.00001).apply(0.912385)
double rounded = Utils.roundDouble(0.912385, 5)
 double a = DoubleRounder.round(2.0/3.0, 3);
 double b = DoubleRounder.round(2.0/3.0, 3, RoundingMode.DOWN);
 double c = DoubleRounder.round(1000.0d, 17);
 double d = DoubleRounder.round(90080070060.1d, 9);
 System.out.println(a);
 System.out.println(b);
 System.out.println(c);
 System.out.println(d);
 0.667
 0.666
 1000.0
 9.00800700601E10
private String withNoTrailingZeros(final double value, final int nrOfDecimals) {
return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals,  BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString();

}
public static final int DECIMAL_PLACES = 2;

NumberFormatter formatter = new NumberFormatter(DECIMAL_PLACES);

String value = formatter.format(9.319); // "9,32"
String value2 = formatter.format(0.0000005); // "5,00E-7"
String value3 = formatter.format(1324134123); // "1,32E9"

double parsedValue1 = formatter.parse("0,4E-2", 0); // 0.004
double parsedValue2 = formatter.parse("0,002", 0); // 0.002
double parsedValue3 = formatter.parse("3423,12345", 0); // 3423.12345
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Locale;

public class NumberFormatter {

    private static final String SYMBOL_INFINITE           = "\u221e";
    private static final char   SYMBOL_MINUS              = '-';
    private static final char   SYMBOL_ZERO               = '0';
    private static final int    DECIMAL_LEADING_GROUPS    = 10;
    private static final int    EXPONENTIAL_INT_THRESHOLD = 1000000000; // After this value switch to exponential notation
    private static final double EXPONENTIAL_DEC_THRESHOLD = 0.0001; // Below this value switch to exponential notation

    private DecimalFormat decimalFormat;
    private DecimalFormat decimalFormatLong;
    private DecimalFormat exponentialFormat;

    private char groupSeparator;

    public NumberFormatter(int decimalPlaces) {
        configureDecimalPlaces(decimalPlaces);
    }

    public void configureDecimalPlaces(int decimalPlaces) {
        if (decimalPlaces <= 0) {
            throw new IllegalArgumentException("Invalid decimal places");
        }

        DecimalFormatSymbols separators = new DecimalFormatSymbols(Locale.getDefault());
        separators.setMinusSign(SYMBOL_MINUS);
        separators.setZeroDigit(SYMBOL_ZERO);

        groupSeparator = separators.getGroupingSeparator();

        StringBuilder decimal = new StringBuilder();
        StringBuilder exponential = new StringBuilder("0.");

        for (int i = 0; i < DECIMAL_LEADING_GROUPS; i++) {
            decimal.append("###").append(i == DECIMAL_LEADING_GROUPS - 1 ? "." : ",");
        }

        for (int i = 0; i < decimalPlaces; i++) {
            decimal.append("#");
            exponential.append("0");
        }

        exponential.append("E0");

        decimalFormat = new DecimalFormat(decimal.toString(), separators);
        decimalFormatLong = new DecimalFormat(decimal.append("####").toString(), separators);
        exponentialFormat = new DecimalFormat(exponential.toString(), separators);

        decimalFormat.setRoundingMode(RoundingMode.HALF_UP);
        decimalFormatLong.setRoundingMode(RoundingMode.HALF_UP);
        exponentialFormat.setRoundingMode(RoundingMode.HALF_UP);
    }

    public String format(double value) {
        String result;
        if (Double.isNaN(value)) {
            result = "";
        } else if (Double.isInfinite(value)) {
            result = String.valueOf(SYMBOL_INFINITE);
        } else {
            double absValue = Math.abs(value);
            if (absValue >= 1) {
                if (absValue >= EXPONENTIAL_INT_THRESHOLD) {
                    value = Math.floor(value);
                    result = exponentialFormat.format(value);
                } else {
                    result = decimalFormat.format(value);
                }
            } else if (absValue < 1 && absValue > 0) {
                if (absValue >= EXPONENTIAL_DEC_THRESHOLD) {
                    result = decimalFormat.format(value);
                    if (result.equalsIgnoreCase("0")) {
                        result = decimalFormatLong.format(value);
                    }
                } else {
                    result = exponentialFormat.format(value);
                }
            } else {
                result = "0";
            }
        }
        return result;
    }

    public String formatWithoutGroupSeparators(double value) {
        return removeGroupSeparators(format(value));
    }

    public double parse(String value, double defValue) {
        try {
            return decimalFormat.parse(value).doubleValue();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return defValue;
    }

    private String removeGroupSeparators(String number) {
        return number.replace(String.valueOf(groupSeparator), "");
    }

}
Math.round(selfEvaluate*100000d.0)/100000d.0;
Math.round(selfEvaluate*100000d.0)*0.00000d1;
Math.round(3.7) // 4
Math.round(3.0); // 3
Math.round(3.1); // 3
Math.round(3.5); // 4
Math.round(3.9); // 4

Math.round(-3.0); // -3
Math.round(-3.1); // -3
Math.round(-3.5); // -3 *** careful here ***
Math.round(-3.9); // -4
Math.ceil(3.0); // 3.0
Math.ceil(3.1); // 4.0
Math.ceil(3.5); // 4.0
Math.ceil(3.9); // 4.0

Math.ceil(-3.0); // -3.0
Math.ceil(-3.1); // -3.0
Math.ceil(-3.5); // -3.0
Math.ceil(-3.9); // -3.0
Math.floor(3.0); // 3.0
Math.floor(3.1); // 3.0
Math.floor(3.5); // 3.0
Math.floor(3.9); // 3.0

Math.floor(-3.0); // -3.0
Math.floor(-3.1); // -4.0
Math.floor(-3.5); // -4.0
Math.floor(-3.9); // -4.0
Math.rint(3.0); // 3.0
Math.rint(3.1); // 3.0
Math.rint(3.5); // 4.0 ***
Math.rint(3.9); // 4.0
Math.rint(4.5); // 4.0 ***
Math.rint(5.5); // 6.0 ***

Math.rint(-3.0); // -3.0
Math.rint(-3.1); // -3.0
Math.rint(-3.5); // -4.0 ***
Math.rint(-3.9); // -4.0
Math.rint(-4.5); // -4.0 ***
Math.rint(-5.5); // -6.0 ***
   public static double round(double value, int precision) {
      int scale = (int) Math.pow(10, precision);
      return (double) Math.round(value * scale) / scale;
  }
double scale = 100000;    
double myVal = 0.912385;
double rounded = (int)((myVal * scale) + 0.5d) / scale;
/**
 * Round half away from zero ('commercial' rounding)
 * Uses correction to offset floating-point inaccuracies.
 * Works symmetrically for positive and negative numbers.
 */
public static double round(double num, int digits) {

    // epsilon correction
    double n = Double.longBitsToDouble(Double.doubleToLongBits(num) + 1);
    double p = Math.pow(10, digits);
    return Math.round(n * p) / p;
}

// test rounding of half
System.out.println(round(0.5, 0));   // 1
System.out.println(round(-0.5, 0));  // -1

// testing edge cases
System.out.println(round(1.005, 2));   // 1.01
System.out.println(round(2.175, 2));   // 2.18
System.out.println(round(5.015, 2));   // 5.02

System.out.println(round(-1.005, 2));  // -1.01
System.out.println(round(-2.175, 2));  // -2.18
System.out.println(round(-5.015, 2));  // -5.02
 DecimalFormat df = new DecimalFormat("#.00");
 String resultado = df.format(valor)
DecimalFormat df = new DecimalFormat("0.00"); :
   private static String getTwoDecimals(double value){
      DecimalFormat df = new DecimalFormat("0.00"); 
      return df.format(value);
    }
91.32
5.22
11.5
1.2
2.6
91.32
5.22
11.50
1.20
2.60
double num = 4.898979485566356;
DecimalFormat df = new DecimalFormat("#.##");      
time = Double.valueOf(df.format(num));

System.out.println(num); // 4.89
BigDecimal bd = new BigDecimal("1363.2749");
bd = bd.setScale(2, RoundingMode.HALF_UP);
System.out.println(bd.doubleValue());
private double round(double value, int places) throws IllegalArgumentException {

    if (places < 0) throw new IllegalArgumentException();

    // Cast the number to a String and then separate the decimals.
    String stringValue = Double.toString(value);
    String decimals = stringValue.split("\\.")[1];

    // Round all the way to the desired number.
    BigDecimal bd = new BigDecimal(stringValue);
    for (int i = decimals.length()-1; i >= places; i--) {
        bd = bd.setScale(i, RoundingMode.HALF_UP);
    }

    return bd.doubleValue();
}
    double amount = 1000.431;        
    NumberFormat formatter = new DecimalFormat("##.00");
    String output = formatter.format(amount);
    System.out.println("output = " + output);
output = 1000.43