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

我想要的是一个方法来将double转换为使用half-up方法进行舍入的string,即,如果小数点要舍入为5,则它总是舍入到前一个数字。 这是大多数人在大多数情况下所期望的四舍五入的标准方法。

我也只想显示有效数字 – 即不应该有任何尾随零。

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

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

收益:

 0.91239 

这是很好的,但是它总是显示5位小数的数字,即使它们不显着:

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

收益:

 0.91230 

另一种方法是使用DecimalFormatter

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

收益:

 0.91238 

但是,正如你所看到的,这使用半双舍入。 如果前面的数字是偶数的话,那就是下降了。 我想要的是这样的:

 0.912385 -> 0.91239 0.912300 -> 0.9123 

在Java中实现这个最好的方法是什么?

使用setRoundingMode ,明确设置RoundingMode来处理你的问题,使用half-even round,然后使用格式模式来输出你需要的结果。

例:

 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 

假设valuedouble ,你可以这样做:

 (double)Math.round(value * 100000d) / 100000d 

这是5位数字的精度。 零的数量表示小数的数量。

 new BigDecimal(String.valueOf(double)).setScale(yourScale, BigDecimal.ROUND_HALF_UP); 

会给你一个BigDecimal 。 要从中取出string,只需调用BigDecimaltoString方法,或者将Java 5+的toPlainString方法调用为普通格式string即可。

示例程序:

 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)); } 

你也可以使用

 DecimalFormat df = new DecimalFormat("#.00000"); df.format(0.912385); 

以确保你有尾随0。

正如其他人所指出的,正确的答案是使用DecimalFormatBigDecimal 。 浮点没有小数位,所以你不可能在第一个位置上舍入/截断它们的特定数目。 你必须使用十进制小数,这就是这两个类所做的。

我将以下代码作为反向示例发布到此线程中的所有答案,并确实遍及StackOverflow(以及其他地方)build议的乘法,接着是截断,接着是除法。 这种技术的倡导者有义务解释为什么下面的代码在超过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"); } } 

这个程序的输出:

 10001 trials 9251 errors 

编辑:我注意到,这个职位已经在这里将近六个月,没有任何解释。 画出自己的结论。

假设你有

 double d = 9232.129394d; 

你可以使用BigDecimal

 BigDecimal bd = new BigDecimal(d).setScale(2, RoundingMode.HALF_EVEN); d = bd.doubleValue(); 

或没有BigDecimal

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

与这两个解决schemed == 9232.13

您可以使用DecimalFormat类。

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

Real的Java How-to 发布了这个解决scheme,它也适用于Java 1.6之前的版本。

 BigDecimal bd = new BigDecimal(Double.toString(d)); bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); return bd.doubleValue(); 
 double myNum = .912385; int precision = 10000; //keep 4 digits myNum= Math.floor(myNum * precision +.5)/precision; 

@Milhous:舍入的十进制格式非常好:

你也可以使用

 DecimalFormat df = new DecimalFormat("#.00000"); df.format(0.912385); 

以确保你有尾随0。

我会补充一点,这个方法非常适合提供一个实际的数字舍入机制 – 不仅在视觉上,而且在处理时。

假设:你必须在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。############”),并且为参数input小数,例如3.1415926,则DecimalFormat不会产生任何垃圾例如,尾随零),并将返回: 3.1415926 ..如果你是这样的倾向。 当然,对于一些开发人员的喜好有点冗长 – 但是,嘿,它在处理过程中占用的内存很less,而且很容易实现。

所以本质上,DecimalFormat的优点在于它同时处理string外观以及舍入精度集合的级别。 Ergo:对于一个代码实现的价格你会得到两个好处。 ;)

您可以使用以下实用程序方法 –

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

这里是你想要的结果作为string你可以使用的总结:

  1. DecimalFormat#setRoundingMode() :

     DecimalFormat df = new DecimalFormat("#.#####"); df.setRoundingMode(RoundingMode.HALF_UP); String str1 = df.format(0.912385)); // 0.91239 
  2. BigDecimal的#setScale()

     String str2 = new BigDecimal(0.912385) .setScale(5, BigDecimal.ROUND_HALF_UP) .toString(); 

如果你想要double的结果,这是一个你可以使用的库的build议。 但是,我不会推荐它用于string转换,因为double可能不能完全代表你想要的东西(例如见这里 ):

  1. 来自Apache Commons Math的精确度

     double rounded = Precision.round(0.912385, 5, BigDecimal.ROUND_HALF_UP); 
  2. 来自Colt的function

     double rounded = Functions.round(0.00001).apply(0.912385) 
  3. 来自Weka的Utils

     double rounded = Utils.roundDouble(0.912385, 5) 

你可以使用BigDecimal

 BigDecimal value = new BigDecimal("2.3"); value = value.setScale(0, RoundingMode.UP); BigDecimal value1 = new BigDecimal("-2.3"); value1 = value1.setScale(0, RoundingMode.UP); System.out.println(value + "n" + value1); 

请参阅: http : //www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

试试这个:org.apache.commons.math3.util.Precision.round(double x,int scale)

请参阅: http : //commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html

Apache Commonsmath图书馆主页是: http : //commons.apache.org/proper/commons-math/index.html

这种方法的内部实现是:

 public static double round(double x, int scale) { return round(x, scale, BigDecimal.ROUND_HALF_UP); } public static double round(double x, int scale, int roundingMethod) { try { return (new BigDecimal (Double.toString(x)) .setScale(scale, roundingMethod)) .doubleValue(); } catch (NumberFormatException ex) { if (Double.isInfinite(x)) { return x; } else { return Double.NaN; } } } 

由于我没有find关于这个主题的完整答案,所以我已经把一个正确处理这个问题的类放在一起,支持:

  • 格式化 :轻松地将double转换为具有一定小数位数的string
  • parsing :将格式化的值parsing为double
  • 区域设置 :使用默认区域设置进行格式和分析
  • 指数表示法 :在一定的阈值之后开始使用指数表示法

用法很简单

(为了这个例子,我使用了一个自定义的语言环境)

 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 

这是class级

 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), ""); } } 

如果你真的想要计算十进制数(而不仅仅是输出),不要使用像double这样的基于二进制的浮点格式。 使用BigDecimal或任何其他基于十进制的格式。 – PaŭloEbermann


我使用BigDecimal进行计算,但请记住它取决于您处理的数字的大小。 在大多数我的实现中,我发现parsing从双或整数到长是足够的,足够大数量的计算。 实际上,我最近使用了parsed-to-Long来获得准确的表示(而不是hex的结果),在gui中的数字大到################## ###############字符(作为例子)。

如果您使用DecimalFormatdouble转换为String ,则非常简单:

 DecimalFormat formatter = new DecimalFormat("0.0##"); formatter.setRoundingMode(RoundingMode.HALF_UP); double num = 1.234567; return formatter.format(num); 

有几个RoundingMode枚举值可供select,具体取决于您所需的行为。

以防万一有人仍然需要帮助。 这个解决scheme对我来说非常合适

 private String withNoTrailingZeros(final double value, final int nrOfDecimals) { return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString(); } 

返回一个String与所需的输出。

下面的代码片段显示了如何显示n个数字。 诀窍是将variablespp设置为1,然后再设置n个零。 在下面的例子中,variablespp值有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(); 

我来这里只是想简单的回答一个数字。 这是提供的补充答案。

如何用Java对数字进行舍入

最常见的情况是使用Math.round()

 Math.round(3.7) // 4 

数字四舍五入到最接近的整数。 一个.5值被四舍五入。 如果您需要不同的舍入行为,则可以使用其他math函数之一。 看下面的比较。

回合

如上所述,这个轮到最接近的整数。 .5小数点四舍五入。 这个方法返回一个int

 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 

小区

任何十进制值四舍五入到下一个整数。 它进入上限 。 这个方法返回一个double

 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 

地板

任何十进制值向下舍入到下一个整数。 这个方法返回一个double

 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 

RINT

这与十进制值四舍五入到最接近的整数类似。 但是,与round不同, .5值会舍入到偶数。 这个方法返回一个double

 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 *** 

我同意select使用DecimalFormat答案—或者BigDecimal

请先阅读下面的更新

但是,如果您希望将double值舍入并获得double值结果,则可以使用上面提到的org.apache.commons.math3.util.Precision.round(..) 该实现使用BigDecimal ,速度慢,并创build垃圾。

DoubleRounder实用程序在decimal4j库中提供了类似但快速且无垃圾的方法:

  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 

请参阅https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility

免责声明:我参与了decimal4j项目。

更新:正如@iaforek指出,DoubleRounder有时会返回违反直觉的结果。 原因是它执行math上正确的四舍五入。 例如DoubleRounder.round(256.025d, 2)将向下取整为256.02,因为256.025d的double值略小于理性值256.025,因此将向下取整。

笔记:

  • 这种行为非常类似于BigDecimal(double)构造函数(但不包括使用string构造函数的valueOf(double) )。
  • 这个问题可以通过双舍入步骤来避免,首先是更高的精度,但是这个问题很复杂,我不打算在这里详细讨论

由于这些原因和上面提到的一切,我不能推荐使用DoubleRounder

这是jpdymond提供的基本解决scheme:

  public static double round(double value, int precision) { int scale = (int) Math.pow(10, precision); return (double) Math.round(value * scale) / scale; } 

https://stackoverflow.com/a/22186845/212950

DecimalFormat是输出的最佳方法,但我不喜欢它。 我总是这样做,因为它返回双重价值。 所以我可以使用它不仅仅是输出。

 Math.round(selfEvaluate*100000d.0)/100000d.0; 

要么

 Math.round(selfEvaluate*100000d.0)*0.00000d1; 

如果您需要大小数位数,则可以使用BigDecimal。 无论如何.0是重要的。 没有它,0.33333d5舍入返回0.33333,只允许9位数字。 没有.0的第二个函数有0.30000的返回值为0.30000000000000004。

其中dp =你想要的小数位数, 是双精度

  double p = Math.pow(10d, dp); double result = Math.round(value * p)/p; 

请记住,String.format()和DecimalFormat会使用默认的Locale生成string。 所以他们可以用点或逗号分隔整数和小数部分的格式。 要确保四舍五入的string是你想要使用java.text.NumberFormat的格式:

  Locale locale = Locale.ENGLISH; NumberFormat nf = NumberFormat.getNumberInstance(locale); // for trailing zeros: nf.setMinimumFractionDigits(2); // round to 2 digits: nf.setMaximumFractionDigits(2); System.out.println(nf.format(.99)); System.out.println(nf.format(123.567)); System.out.println(nf.format(123.0)); 

将以英文语言环境打印(不pipe您的语言环境如何):0.99 123.57 123.00

该示例取自Farenda – 如何正确地将double转换为String 。

如果你考虑5或n小数。 可能是这个答案解决你的概率。

  double a = 123.00449; double roundOff1 = Math.round(a*10000)/10000.00; double roundOff2 = Math.round(roundOff1*1000)/1000.00; double roundOff = Math.round(roundOff2*100)/100.00; System.out.println("result:"+roundOff); 

输出将是: 123.0 1
这可以用循环和recursion函数来解决。

 DecimalFormat myFormatter = new DecimalFormat("0.000"); String output = myFormatter.format(2.34d); 

基本上, round()方法返回最接近的longint ,如方法的返回types所示:

 public class Test{ public static void main(String args[]){ double d = 100.675; double e = 100.500; float f = 100; float g = 90f; System.out.println (Math.round(d)); System.out.println (Math.round(e)); System.out.println (Math.round(f)); System.out.println (Math.round(g)); } } 

这给出了输出:

 101 101 100 90