How to round a number to n decimal places in Java
我想要的是一种将双精度数转换为字符串的方法,该字符串使用半向上方法进行舍入-即,如果要舍入的十进制数为5,则它总是向上舍入到前一个数字。这是大多数人在大多数情况下期望的标准舍入方法。
我也希望只显示有效数字-也就是说,不应该有任何尾随的零。
我知道这样做的一种方法是使用
1 |
返回:
1 | 0.91239 |
很好,但是它总是显示小数点后5位的数字,即使它们不重要:
1 |
返回:
1 | 0.91230 |
另一种方法是使用
1 2 |
返回:
1 | 0.91238 |
但是,正如您所看到的,这使用了半偶数取整。也就是说,如果前一个数字是偶数,它将向下取整。我想要的是:
1 2 | 0.912385 -> 0.91239 0.912300 -> 0.9123 |
在Java中实现这个最好的方法是什么?
使用
例子:
1 2 3 4 5 6 | 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)); } |
给出输出:
1 2 3 4 5 | 12 123.1235 0.23 0.1 2341234.2125 |
假设
1 |
精确到5位数。零的数目表示小数的数目。
1 |
会给你买一辆
样本程序:
1 2 3 4 5 6 7 8 9 | 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)); } |
您也可以使用
1 2 |
以确保后面有0。
假设你有
1 | double d = 9232.129394d; |
您可以使用
1 2 |
或不带BigDecimal
1 |
使用两种解决方案
正如其他一些人所指出的,正确的答案是使用
我将把下面的代码作为一个反例发布到这个线程中的所有答案上,甚至在StackOverflow(和其他地方)上,它建议先乘后截断,再除以。这种技术的倡导者有责任解释为什么下面的代码在92%以上的情况下产生错误的输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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"); } } |
本程序输出:
1 | 10001 trials 9251 errors |
编辑:为了解决下面的一些意见,我使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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"); } |
结果:
1 | 10001 trials 4401 errors |
您可以使用decimalformat类。
1 2 3 4 | double d = 3.76628729; DecimalFormat newFormat = new DecimalFormat("#.##"); double twoDecimal = Double.valueOf(newFormat.format(d)); |
Realm的Java如何发布这个解决方案,它也兼容Java 1.6之前的版本。
1 2 3 | BigDecimal bd = new BigDecimal(Double.toString(d)); bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP); return bd.doubleValue(); |
1 2 3 | double myNum = .912385; int precision = 10000; //keep 4 digits myNum= Math.floor(myNum * precision +.5)/precision; |
@milhous:舍入的十进制格式非常好:
You can also use the
1
2to make sure you have the trailing 0's.
我想补充一下,这个方法非常擅长提供数字,舍入机制-不仅在视觉上,而且在处理时。
假设:您必须在GUI中实现舍入机制程序。简单地改变结果输出的精度更改插入符号格式(即括号内)。以便:
1 2 |
将作为输出返回:
1 2 |
将作为输出返回:
1 2 |
将作为输出返回:
[编辑:如果插入符号格式是这样的("0."),那么您输入一个小数,例如3.1415926,作为参数,decimalFormat不产生任何垃圾(例如尾随零),将返回:
因此,本质上,decimalformat的优点在于它同时处理字符串外观-以及舍入精度集的级别。埃尔戈:你以一个代码实现的价格获得两个好处。;)
您可以使用以下实用程序方法-
1 2 3 4 5 6 |
这里是一个总结,如果你想你可以使用一个字符串:
decimalformat # setroundingmode():
1 2 3 | DecimalFormat df = new DecimalFormat("#.#####"); df.setRoundingMode(RoundingMode.HALF_UP); String str1 = df.format(0.912385)); // 0.91239 |
# BigDecimal setscale()
1 2 3 |
这里是一个建议,你可以使用什么库,如果你想
从Apache Commons数学精度
1 |
函数从小马
1 | double rounded = Functions.round(0.00001).apply(0.912385) |
在weka工具
1 | double rounded = Utils.roundDouble(0.912385, 5) |
简洁的解决方案:
1 2 3 4 |
另请参阅,https://stackoverflow.com/a/22186845/212950感谢JPDymond提供此服务。
你可以使用BigDecimal
1 2 3 4 5 | 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 /精密工程学院的小数被使用-被枚举/时尚
如果您真的想计算十进制数(不仅是输出十进制数),不要使用基于二进制的浮点格式,如double。
1 | Use BigDecimal or any other decimal-based format. |
我确实使用bigdecimal进行计算,但请记住,它取决于你要处理的数字。在我的大多数实现中,我发现从double或整数到长的长度足以进行非常大的数值计算。
事实上,我已经最近使用的解析为long以获得准确的表示(而不是十六进制结果)在一个图形用户界面中,数字的大小为\\3535353535\3535\\\35\35\35\35\\\35\___字符(作为例子)。
试试这个:org.apache.commons.math3.util.precision.round(double x,int量表)
湖:http://commons.apache.org /正确/共享/组织/数学/ apidocs Apache Commons math3 util / / / / precision.html
Apache Commons数学图书馆主页是:http://commons.apache.org /数学/共享服务。
内部implemetation本法是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } } } |
自从我找到完整的答案没有在这个主题我已经把那本应在一级处理,以支持:
- 格式:格式字符串和一双的一个十进制数的某些地方
- 解析:解析格式化值的双回
- 现场:现场使用默认格式和解析
- 指数记数法:开始使用指数符号后一定门限
很简单的用法是:
(在这个例子的缘故,我使用自定义设置)
1 2 3 4 5 6 7 8 9 10 11 | 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 |
这里是类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 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),""); } } |
只是在有人需要帮助,与本案例的安静。这个解决方案,我的作品完美。
1 2 3 4 | private String withNoTrailingZeros(final double value, final int nrOfDecimals) { return new BigDecimal(String.valueOf(value)).setScale(nrOfDecimals, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString(); } |
返回a
为此,我们可以使用此格式化程序:
1 2 |
或:
1 |
使用此方法始终获得两个小数:
1 2 3 4 | private static String getTwoDecimals(double value){ DecimalFormat df = new DecimalFormat("0.00"); return df.format(value); } |
定义此值:
1 2 3 4 5 | 91.32 5.22 11.5 1.2 2.6 |
使用这种方法,我们可以得到以下结果:
1 2 3 4 5 | 91.32 5.22 11.50 1.20 2.60 |
在线演示。
如果你使用一个转换
1 2 3 4 5 | DecimalFormat formatter = new DecimalFormat("0.0##"); formatter.setRoundingMode(RoundingMode.HALF_UP); double num = 1.234567; return formatter.format(num); |
有几个
下面的代码段显示了如何显示n位数字。诀窍是将变量pp设置为1,后跟n个零。在下面的示例中,变量pp值有5个零,因此将显示5位数字。
1 2 3 4 5 6 7 8 9 |
我来这里只是想得到一个关于如何取整数字的简单答案。这是一个补充答案。
如何在Java中循环数字最常见的情况是使用
1 |
数字四舍五入为最接近的整数。将
如上所述,这四舍五入为最接近的整数。
1 2 3 4 5 6 7 8 9 |
塞尔
任何十进制值都将被四舍五入到下一个整数。它到了天花板。此方法返回一个
1 2 3 4 5 6 7 8 9 |
地板
任何十进制值都向下舍入为下一个整数。此方法返回一个
1 2 3 4 5 6 7 8 9 |
林特
这类似于将十进制值舍入到最接近的整数。但是,与
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 *** |
我同意与选定的答案用
请读下面的更新第一!
但是如果你做想环游
一个类似的,但几乎无法提供和垃圾是由
1 2 3 4 5 6 7 8 |
想输出
1 2 3 4 | 0.667 0.666 1000.0 9.00800700601E10 |
湖http:/ / / / / github.com tools4j decimal4j维基/ doublerounder效用
免责声明:我decimal4j参与的项目。
更新:作为替代doublerounder @ iaforek counterintuitive有时返回出结果。原因是,它mathematically被正确执行。例如
说明:
- 这种行为是非常类似于《
BigDecimal(double) 构造函数(这是在不到valueOf(double) 使用字符串的构造函数)。 - 一个问题可以被circumvented双降压到一个高精度的第一,但它是复杂的,我不会进入细节在这里
对于那些在这一切以上原因后,很doublerounder i无法使用。
如果您使用的技术具有最小的JDK。这里有一个没有Java LIBS的方法:
1 2 3 | double scale = 100000; double myVal = 0.912385; double rounded = (int)((myVal * scale) + 0.5d) / scale; |
decimalformat是最好的输出方式,但我不喜欢它。我总是这样做,因为它返回双精度值。所以我可以使用它,而不仅仅是输出。
1 |
或
1 |
如果需要大的小数位数值,可以改用BigDecimal。无论如何,
记住,string.format)和字符串(默认decimalformat生产现场使用。所以他们可以写一点格式化数或逗号作为十进制整数和分离器之间的配件。这是为了确保储存格式字符串中使用java.text.numberformat:你想要的那样
1 2 3 4 5 6 7 8 9 10 | 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)); |
要打印的区域(不知道你的英语是:现场)0.99y=8.8608x~2-110.8516x+330.6251.123.00
的例子是从farenda如何采取正确的字符串转换为双。
如果你考虑N 5或十进制数。解决这个问题可能是你的答案。
1 2 3 4 5 6 |
要:123.01输出>本可以解决与循环和递归函数。
一般来说,舍入是通过缩放来完成的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /** * MidpointRounding away from zero ('arithmetic' rounding) * Uses a half-epsilon for correction. (This offsets IEEE-754 * half-to-even rounding that was applied at the edge cases). */ double RoundCorrect(double num, int precision) { double c = 0.5 * EPSILON * num; // double p = Math.pow(10, precision); //slow double p = 1; while (precision--> 0) p *= 10; if (num < 0) p *= -1; return Math.round((num + c) * p) / p; } // testing edge cases RoundCorrect(1.005, 2); // 1.01 correct RoundCorrect(2.175, 2); // 2.18 correct RoundCorrect(5.015, 2); // 5.02 correct RoundCorrect(-1.005, 2); // -1.01 correct RoundCorrect(-2.175, 2); // -2.18 correct RoundCorrect(-5.015, 2); // -5.02 correct |
在DP =十进制的地方你想要的。价值是一个双。