题
什么我会喜欢的方法来转换一个双向字符串回合使用的一半,方法-即如果小数点是圆的是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
明确地处理半偶数问题,然后使用格式模式进行所需的输出。
示例:
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
其他提示
假设 value
是 double
,你可以这样做:
(double)Math.round(value * 100000d) / 100000d
这是5位精度。零的数量表示小数位数。
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));
}
您也可以使用
DecimalFormat df = new DecimalFormat("#.00000");
df.format(0.912385);
确保你有0的结尾。
正如其他人所说,正确的答案是使用 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");
}
}
该计划的输出:
10001 trials 9251 errors
编辑:为了解决下面的一些评论,我使用 BigDecimal
和 new MathContext(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");
}
结果:
10001 trials 4401 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;
两个解决方案 d == 9232.13
您可以使用DecimalFormat类。
double d = 3.76628729;
DecimalFormat newFormat = new DecimalFormat("#.##");
double twoDecimal = Double.valueOf(newFormat.format(d));
Real的Java How-to 发布此解决方案,该解决方案也兼容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。############”)并且你
输入小数,例如3.1415926,为了论证,DecimalFormat
不产生任何垃圾(例如尾随零)并将返回:
3.1415926
..如果你这样倾向。当然,它有点冗长
对于一些开发人员的喜好 - 但是嘿,它的内存占用很少
在处理过程中非常容易实现。]
基本上,DecimalFormat的优点在于它同时处理字符串 外观 - 以及舍入精度设置的级别。 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:
,可以使用以下内容摘要-
DecimalFormat #setRoundingMode():
DecimalFormat df = new DecimalFormat("#.#####"); df.setRoundingMode(RoundingMode.HALF_UP); String str1 = df.format(0.912385)); // 0.91239
-
String str2 = new BigDecimal(0.912385) .setScale(5, BigDecimal.ROUND_HALF_UP) .toString();
醇>
如果您希望 double
,可以使用哪些库。我不建议将其用于字符串转换,因为double可能无法准确表示您想要的内容(请参阅此处一>):
简洁的解决方案:
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 感谢 jpdymond 提供此功能。
您可以使用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);
试试这个:org.apache.commons.math3.util.Precision.round(double x,int scale)
请参阅: http://commons.apache .ORG /正确/公地数学/ apidocs /组织/阿帕奇/公地/ MATH3 / util的/ Precision.html
Apache Commons数学图书馆主页是: http://commons.apache.org/proper/commons-数学/ 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;
}
}
}
如果你真的想要十进制数来计算(而不仅仅是输出),不要使用像double这样的基于二进制的浮点格式。
Use BigDecimal or any other decimal-based format.
我确实使用BigDecimal进行计算,但要记住它取决于大小 你正在处理的数字。在我的大多数实现中,我发现从double或者解析 整数到Long足以进行大量计算。
事实上,我已经 最近使用parsed-to-Long来获得准确的表示(与hex结果相反) 在GUI中,数字与#################################字符一样大(作为 例子)。
因为我发现没有完全回答关于这个主题我已经把一级,应该处理这一点正确,与支持:
- 格式化:容格式的双串有一定数量的小数位
- 析:分析的格式化的价值回到双
- 区域:格式和分析使用的默认区域
- 指数符号:开始使用指数符号之后的某一阈值
用法很简单:
(为了这个例子中,我使用一个定制的区域)
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), "");
}
}
以防有人仍然需要帮助。这个解决方案非常适合我。
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位数。诀窍是将变量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
转换为 String
,那么它非常简单:
DecimalFormat formatter = new DecimalFormat("0.0##");
formatter.setRoundingMode(RoundingMode.HALF_UP);
double num = 1.234567;
return formatter.format(num);
有几个 RoundingMode
枚举值可供选择,具体取决于您需要的行为。
我来到这里只是想要一个关于如何围绕数字的简单答案。这是提供这一点的补充答案。
如何在Java中对数字进行舍入
最常见的情况是使用 Math.round()
。
Math.round(3.7) // 4
数字四舍五入到最接近的整数。向上舍入 .5
值。如果你需要不同的舍入行为,你可以使用另一个数学功能。请参阅下面的比较。
round
如上所述,这轮到最接近的整数。 .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
ceil
任何十进制值都会向上舍入到下一个整数。它进入了 ceil 。此方法返回 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,十进制值四舍五入到最接近的整数。但是,与 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 ***
为实现这一目标,我们可以使用此格式化程序:
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
我同意所选择的回答使用 DecimalFormat
---或者 BigDecimal
.
请阅读 更新 下面第一!
但是如果你 做 想一轮的双重价值,并得到一个 double
值结果,可以使用 org.apache.commons.math3.util.Precision.round(..)
如上所述。执行使用 BigDecimal
, 是缓慢的,并创建的垃圾。
一个类似的但是快和垃圾的方法是提供通过 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有时返回有悖常理的结果。其原因是,它执行数学上正确四舍五入。例如 DoubleRounder.round(256.025d, 2)
将向下调整至256.02因为双值表示为256.025d是有点小于合理价值256.025,因此将四舍五入下降。
注:
- 这种行为是非常相似的
BigDecimal(double)
构造(但不要valueOf(double)
其使用的字符串constructor). - 问题是可以避免与双四舍五入的步骤,以较高的精确度第一,但它是复杂的,我不会详述这里
由于这些原因的一切,上面提到的在这个岗位我 不建议使用DoubleRounder.
如果您使用的是具有最小JDK的技术。这是一种没有任何Java库的方法:
double scale = 100000;
double myVal = 0.912385;
double rounded = (int)((myVal * scale) + 0.5d) / scale;
DecimalFormat是输出的最佳方式,但我不喜欢它。我总是这样做,因为它返回double值。所以我可以使用它而不仅仅是输出。
Math.round(selfEvaluate*100000d.0)/100000d.0;
OR
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符合您想要的格式,请使用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));
将以英语区域设置打印(无论您的语言环境是什么): 0.99 123.57 123.00
该示例取自Farenda - 如何将双倍转换为字符串正确。
如果考虑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
这可以通过循环和递归函数来解决。
通常,舍入是通过缩放来完成的: round(num / p)* p
/**
* 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