Java中如何将数字四舍五入到小数点后n位
我想要的是一种将双精度数转换为使用半向上方法舍入的字符串的方法 - 即,如果要舍入的小数是 5,它总是向上舍入到下一个数字。 这是大多数人在大多数情况下所期望的四舍五入的标准方法。
我还希望只显示有效数字 - 即不应有任何尾随零。
我知道这样做的一种方法是使用 String.format
方法:
String.format("%.5g%n", 0.912385);
returns:
0.91239
这很好,但是它总是显示小数点后 5 位的数字,即使它们不重要:
String.format("%.5g%n", 0.912300);
returns:
0.91230
另一种方法是使用DecimalFormatter
:
DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
返回:
0.91238
但是,正如您所看到的,这使用了半偶数舍入。 也就是说,如果前一位数字是偶数,则向下舍入。 我想要的是:
0.912385 -> 0.91239
0.912300 -> 0.9123
在 Java 中实现此目的的最佳方法是什么?
What I would like is a method to convert a double to a string which rounds using the half-up method - i.e. if the decimal to be rounded is 5, it always rounds up to the next number. This is the standard method of rounding most people expect in most situations.
I also would like only significant digits to be displayed - i.e. there should not be any trailing zeroes.
I know one method of doing this is to use the String.format
method:
String.format("%.5g%n", 0.912385);
returns:
0.91239
which is great, however it always displays numbers with 5 decimal places even if they are not significant:
String.format("%.5g%n", 0.912300);
returns:
0.91230
Another method is to use the DecimalFormatter
:
DecimalFormat df = new DecimalFormat("#.#####");
df.format(0.912385);
returns:
0.91238
However as you can see this uses half-even rounding. That is it will round down if the previous digit is even. What I'd like is this:
0.912385 -> 0.91239
0.912300 -> 0.9123
What is the best way to achieve this in Java?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
如果您确实需要十进制数进行计算(而不仅仅是输出),请不要使用基于二进制的浮点格式(如 double)。
我确实使用 BigDecimal 进行计算,但请记住它取决于
您正在处理的数字。 在我的大多数实现中,我发现从 double 或
整数到 Long 足以进行非常大的数字计算。
事实上,我已经
最近使用 parsed-to-Long 来获得准确的表示(而不是十六进制结果)
在 GUI 中,对于像 ################################### 个字符一样大的数字(作为
例子)。
If you really want decimal numbers for calculation (and not only for output), do not use a binary-based floating point format like double.
I do use BigDecimal for calculations, but bear in mind it is dependent on the size of
numbers you're dealing with. In most of my implementations, I find parsing from double or
integer to Long is sufficient enough for very large number calculations.
In fact, I've
recently used parsed-to-Long to get accurate representations (as opposed to hex results)
in a GUI for numbers as big as ################################# characters (as an
example).
试试这个: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 Commons数学图书馆主页是: http://commons.apache.org/proper/commons-math/index.html
该方法的内部实现是:
Try this: org.apache.commons.math3.util.Precision.round(double x, int scale)
See: http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html
Apache Commons Mathematics Library homepage is: http://commons.apache.org/proper/commons-math/index.html
The internal implemetation of this method is:
因为我没有找到关于这个主题的完整答案,所以我整理了一个应该正确处理这个问题的类,并支持:
>使用非常简单:(
在本示例中,我使用自定义语言环境)
这是类:
Since I found no complete answer on this theme I've put together a class that should handle this properly, with support for:
Usage is pretty simple:
(For the sake of this example I am using a custom locale)
Here is the class:
以防万一有人仍然需要帮助。 这个解决方案非常适合我。
返回带有所需输出的
String
。Just in case someone still needs help with this. This solution works perfectly for me.
returns a
String
with the desired output.我来这里只是想得到一个关于如何四舍五入数字的简单答案。 这是提供这一点的补充答案。
如何在 Java 中对数字进行舍入
最常见的情况是使用 Math.round()。
数字四舍五入到最接近的整数。
.5
值会向上舍入。 如果您需要不同的舍入行为,则可以使用其他之一 数学函数。 请参阅下面的比较。round
如上所述,四舍五入到最接近的整数。
.5
小数点向上舍入。 此方法返回一个int
。ceil
任何十进制值向上舍入到下一个整数。 它已经达到了天花板。 此方法返回一个
double
。floor
任何十进制值向下舍入到下一个整数。 此方法返回一个
double
。rint
这很相似将小数值四舍五入到最接近的整数。 但是,与
round
不同,.5
值舍入为偶数。 此方法返回一个double
。I came here just wanting a simple answer on how to round a number. This is a supplemental answer to provide that.
How to round a number in Java
The most common case is to use
Math.round()
.Numbers are rounded to the nearest whole number. A
.5
value is rounded up. If you need different rounding behavior than that, you can use one of the other Math functions. See the comparison below.round
As stated above, this rounds to the nearest whole number.
.5
decimals round up. This method returns anint
.ceil
Any decimal value is rounded up to the next integer. It goes to the ceiling. This method returns a
double
.floor
Any decimal value is rounded down to the next integer. This method returns a
double
.rint
This is similar to round in that decimal values round to the closest integer. However, unlike
round
,.5
values round to the even integer. This method returns adouble
.我同意使用
DecimalFormat
--- 或BigDecimal
所选择的答案。请先阅读下面的更新!
但是,如果您确实想要对双精度值进行四舍五入并获得双精度
值结果,则可以使用org.apache.commons.math3.util。 Precision.round(..)
如上所述。 该实现使用BigDecimal
,速度慢并且会产生垃圾。decimal4j 中的DoubleRounder
实用程序提供了类似但快速且无垃圾的方法库:将输出
参见
https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility
披露:我参与了decimal4j 项目。
更新:
正如 @iaforek 指出的那样,DoubleRounder 有时会返回违反直觉的结果。 原因是它执行数学上正确的舍入。 例如,
DoubleRounder.round(256.025d, 2)
将向下舍入为 256.02,因为表示为 256.025d 的 double 值略小于有理值 256.025,因此将向下舍入。注释:
BigDecimal(double)
构造函数非常相似(但与使用字符串构造函数的valueOf(double)
不同) )。出于这些原因以及本文上面提到的所有内容,我不建议使用 DoubleRounder。
I agree with the chosen answer to use
DecimalFormat
--- or alternativelyBigDecimal
.Please read Update below first!
However if you do want to round the double value and get adouble
value result, you can useorg.apache.commons.math3.util.Precision.round(..)
as mentioned above. The implementation usesBigDecimal
, is slow and creates garbage.A similar but fast and garbage-free method is provided by theDoubleRounder
utility in the decimal4j library:Will output
See
https://github.com/tools4j/decimal4j/wiki/DoubleRounder-Utility
Disclosure: I am involved in the decimal4j project.
Update:
As @iaforek pointed out DoubleRounder sometimes returns counterintuitive results. The reason is that it performs mathematically correct rounding. For instance
DoubleRounder.round(256.025d, 2)
will be rounded down to 256.02 because the double value represented as 256.025d is somewhat smaller than the rational value 256.025 and hence will be rounded down.Notes:
BigDecimal(double)
constructor (but not tovalueOf(double)
which uses the string constructor).For those reasons and everything mentioned above in this post I cannot recommend to use DoubleRounder.
因此,在阅读了大部分答案后,我意识到其中大多数答案都不精确,事实上使用 BigDecimal 似乎是最好的选择,但如果您不明白 RoundingMode 是如何实现的/code> 有效,你将不可避免地失去精度。 我在项目中处理大数字时发现了这一点,并认为它可以帮助其他人在四舍五入数字时遇到困难。 例如。
您希望得到
1363.28
作为输出,但最终会得到1363.27
,如果您不知道RoundingMode< 是什么,这不是预期的结果/code> 正在做。 因此,查看 Oracle 文档,您将查找
RoundingMode.HALF_UP
的以下描述。因此,了解了这一点,我们意识到我们不会得到精确的舍入,除非我们想向最近的邻居舍入。 因此,为了完成足够的轮次,我们需要从 n-1 小数点循环到所需的小数位数。 例如。
这最终将为我们提供预期的输出,即
1363.28
。So after reading most of the answers, I realized most of them won't be precise, in fact using
BigDecimal
seems like the best choice, but if you don't understand how theRoundingMode
works, you will inevitable lose precision. I figured this out when working with big numbers in a project and thought it could help others having trouble rounding numbers. For example.You would expect to get
1363.28
as an output, but you will end up with1363.27
, which is not expected, if you don't know what theRoundingMode
is doing. So looking into the Oracle Docs, you will find the following description forRoundingMode.HALF_UP
.So knowing this, we realized that we won't be getting an exact rounding, unless we want to round towards nearest neighbor. So, to accomplish an adequate round, we would need to loop from the
n-1
decimal towards the desired decimals digits. For example.This will end up giving us the expected output, which would be
1363.28
.如果您使用
DecimalFormat
将double
转换为String
,则非常简单:有多个
RoundingMode
枚举值根据您需要的行为进行选择。If you're using
DecimalFormat
to convertdouble
toString
, it's very straightforward:There are several
RoundingMode
enum values to select from, depending upon the behaviour you require.如果您使用的技术具有最小的 JDK。 这是一种没有任何 Java 库的方法:
If you're using a technology that has a minimal JDK. Here's a way without any Java libs:
这是我的答案:
here is my answer:
这是一个更好的函数,可以正确舍入像
1.005
这样的边缘情况。简而言之,我们在四舍五入之前将尽可能小的浮点值(= 1 ulp;最后一位的单位)添加到数字中。 这将移动到数字之后的下一个可表示的值,远离零。
这是一个测试它的小程序:ideone.com
Here is a better function that rounds edge cases like
1.005
correctly.Simply, we add the smallest possible float value (= 1 ulp; unit in the last place) to the number before rounding. This moves to the next representable value after the number, away from zero.
This is a little program to test it: ideone.com
下面的代码片段展示了如何显示n位数字。 技巧是将变量 pp 设置为 1,后跟 n 个零。 在下面的示例中,变量 pp 值有 5 个零,因此将显示 5 位数字。
The code snippet below shows how to display n digits. The trick is to set variable pp to 1 followed by n zeros. In the example below, variable pp value has 5 zeros, so 5 digits will be displayed.
DecimalFormat 是最好的输出方式,但我不喜欢它。 我总是这样做,因为它返回双精度值。 所以我可以使用它而不仅仅是输出。
或者
如果您需要大的小数位值,您可以使用 BigDecimal 代替。 无论如何
.0
很重要。 如果没有它,0.33333d5 的舍入将返回 0.33333,并且只允许 9 位数字。 没有.0
的第二个函数存在 0.30000 返回 0.30000000000000004 的问题。DecimalFormat is the best ways to output, but I don't prefer it. I always do this all the time, because it return the double value. So I can use it more than just output.
OR
If you need large decimal places value, you can use BigDecimal instead. Anyways
.0
is important. Without it the rounding of 0.33333d5 return 0.33333 and only 9 digits are allows. The second function without.0
has problems with 0.30000 return 0.30000000000000004.我像在java 8中一样使用了波纹管。它对我有用
输出:
I have used bellow like in java 8. it is working for me
Output:
如果需要
double
,可以使用以下方法,例如
getRandom(2)
the following method could be used if need
double
for example
getRandom(2)
使用
setRoundingMode
,设置< code>RoundingMode 显式地处理半偶数轮的问题,然后使用所需输出的格式模式。示例:
给出输出:
编辑:原始答案没有解决双精度值的准确性。 如果您不太关心它是向上还是向下舍入,那很好。 但如果您想要精确舍入,那么您需要考虑值的预期精度。 浮点值在内部具有二进制表示形式。 这意味着像 2.7735 这样的值实际上在内部并不具有该精确值。 它可以稍大或稍小。 如果内部值稍小,则不会向上舍入为 2.7740。 为了解决这种情况,您需要了解正在使用的值的准确性,并在舍入之前添加或减去该值。 例如,当您知道您的值最多精确到 6 位数字时,要将中间值向上舍入,请将该精度添加到该值中:
要向下舍入,请减去该精度。
Use
setRoundingMode
, set theRoundingMode
explicitly to handle your issue with the half-even round, then use the format pattern for your required output.Example:
gives the output:
EDIT: The original answer does not address the accuracy of the double values. That is fine if you don't care much whether it rounds up or down. But if you want accurate rounding, then you need to take the expected accuracy of the values into account. Floating point values have a binary representation internally. That means that a value like 2.7735 does not actually have that exact value internally. It can be slightly larger or slightly smaller. If the internal value is slightly smaller, then it will not round up to 2.7740. To remedy that situation, you need to be aware of the accuracy of the values that you are working with, and add or subtract that value before rounding. For example, when you know that your values are accurate up to 6 digits, then to round half-way values up, add that accuracy to the value:
To round down, subtract the accuracy.
假设
value
是一个double
,您可以这样做:这是 5 位精度。 零的个数表示小数点的个数。
Assuming
value
is adouble
, you can do:That's for 5 digits precision. The number of zeros indicate the number of decimals.
将为您提供一个
BigDecimal
。 要从中获取字符串,只需调用BigDecimal
的toString
方法,或者调用 Java 5+ 的toPlainString
方法以获得纯格式细绳。示例程序:
will get you a
BigDecimal
. To get the string out of it, just call thatBigDecimal
'stoString
method, or thetoPlainString
method for Java 5+ for a plain format string.Sample program:
您还可以使用 来
确保尾随 0。
You can also use the
to make sure you have the trailing 0's.
正如其他一些人所指出的,正确的答案是使用
DecimalFormat
或BigDecimal
。 浮点数没有小数位,因此您不可能首先舍入/截断到特定数量的小数位。 您必须使用十进制基数,这就是这两个类的作用。我发布以下代码作为该线程中所有答案的反例,实际上整个 StackOverflow(和其他地方)都建议先乘法,然后截断,然后除法。 该技术的倡导者有责任解释为什么以下代码在超过 92% 的情况下会产生错误的输出。
该程序的输出:
编辑:为了解决下面的一些评论,我使用
BigDecimal
和new MathContext(16)
重新编辑了测试循环的模数部分求模运算如下:结果:
As some others have noted, the correct answer is to use either
DecimalFormat
orBigDecimal
. Floating-point doesn't have decimal places so you cannot possibly round/truncate to a specific number of them in the first place. You have to work in a decimal radix, and that is what those two classes do.I am posting the following code as a counter-example to all the answers in this thread and indeed all over StackOverflow (and elsewhere) that recommend multiplication followed by truncation followed by division. It is incumbent on advocates of this technique to explain why the following code produces the wrong output in over 92% of cases.
Output of this program:
EDIT: To address some comments below I redid the modulus part of the test loop using
BigDecimal
andnew MathContext(16)
for the modulus operation as follows:Result:
假设您
可以使用
BigDecimal
或不使用 BigDecimal
并使用两种解决方案
d == 9232.13
Suppose you have
you can use
BigDecimal
or without BigDecimal
with both solutions
d == 9232.13
您可以使用 DecimalFormat 类。
You can use the DecimalFormat class.
Real 的 Java How-to 帖子 这个解决方案,它也兼容 Java 之前的版本1.6.
更新:BigDecimal.ROUND_HALF_UP 已弃用 - 使用 RoundingMode
Real's Java How-to posts this solution, which is also compatible for versions before Java 1.6.
UPDATE: BigDecimal.ROUND_HALF_UP is deprecated - Use RoundingMode
@Milhous:舍入的十进制格式非常好:
我想补充一点,这种方法非常擅长提供实际的
数字、舍入机制 - 不仅在视觉上,而且在处理时也是如此。
假设:您必须在 GUI 中实现舍入机制
程序。 简单地改变结果输出的准确度/精度
更改插入符号格式(即在括号内)。 这样:
将返回作为输出:
0.912385
将返回作为输出:
0.91239
将返回作为输出:
0.9124
[编辑:如果插入符号格式也是如此就像这样(“#0.############”)而你
输入一个小数,例如 3.1415926,为了论证,DecimalFormat
不会产生任何垃圾(例如尾随零)并将返回:
3.1415926
..如果你有这样的倾向。 当然,这有点冗长为了满足一些开发人员的喜好 - 但是嘿,它的内存占用很低
]
因此,从本质上讲,DecimalFormat 的优点在于它同时处理字符串
外观——以及舍入精度设置的水平。 因此:你
以执行一种代码的价格获得两种好处。 ;)
@Milhous: the decimal format for rounding is excellent:
I would add that this method is very good at providing an actual
numeric, rounding mechanism - not only visually, but also when processing.
Hypothetical: you have to implement a rounding mechanism into a GUI
program. To alter the accuracy / precision of a result output simply
change the caret format (i.e. within the brackets). So that:
would return as output:
0.912385
would return as output:
0.91239
would return as output:
0.9124
[EDIT: also if the caret format is like so ("#0.############") and you
enter a decimal, e.g. 3.1415926, for argument's sake, DecimalFormat
does not produce any garbage (e.g. trailing zeroes) and will return:
3.1415926
.. if you're that way inclined. Granted, it's a little verbosefor the liking of some dev's - but hey, it's got a low memory footprint
during processing and is very easy to implement.]
So essentially, the beauty of DecimalFormat is that it simultaneously handles the string
appearance - as well as the level of rounding precision set. Ergo: you
get two benefits for the price of one code implementation. ;)
如果您希望结果为字符串,以下是您可以使用的摘要:
DecimalFormat#setRoundingMode():
BigDecimal#setScale()
如果您想要
double
结果,这里建议您可以使用哪些库。 不过,我不建议将其用于字符串转换,因为 double 可能无法准确表示您想要的内容(请参见此处):精度 来自 Apache Commons Math
Colt 的函数
实用工具来自Weka
Here is a summary of what you can use if you want the result as String:
DecimalFormat#setRoundingMode():
BigDecimal#setScale()
Here is a suggestion of what libraries you can use if you want
double
as a result. I wouldn't recommend it for string conversion, though, as double may not be able to represent what you want exactly (see e.g. here):Precision from Apache Commons Math
Functions from Colt
Utils from Weka
您可以使用以下实用方法 -
You could use the following utility method-
简洁的解决方案:
另请参阅https://stackoverflow.com/a/22186845/212950
感谢 jpdymond 提供此内容。
编辑:添加圆括号。 将整个结果转换为双精度,而不仅仅是第一个参数!
A succinct solution:
See also, https://stackoverflow.com/a/22186845/212950
Thanks to jpdymond for offering this.
Edit: Added round brackets. Casts the whole result to double, not the first argument only!
您可以使用 BigDecimal
参考:http://www.javabeat.net/precise -使用舍入模式枚举的小数舍入/
You can use BigDecimal
Refer: http://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/
为了实现这一点,我们可以使用此格式化程序:
或者:
使用此方法始终获取两位小数:
定义此值:
使用该方法我们可以获得此结果:
在线演示。
To achieve this we can use this formatter:
or:
Use this method to get always two decimals:
Defining this values:
Using the method we can get this results:
demo online.