Java中Math.rint()和Math.round()的区别

21

Math.rint()Math.round()有什么区别?


1
一个非常有用的Code Ranch帖子:http://www.coderanch.com/t/239803/java-programmer-OCPJP/certification/Difference-rint-methods-Math-class。`Math.rint()`和`Math.round()`对于恰好处于两个整数之间的输入表现不同。 - Tim Biegeleisen
3
如果你能够添加一些内容,那就应该是一个答案了。 - Makoto
7个回答

19

Math.rint()Math.round()有几个不同之处,但可能对Java应用程序的业务逻辑影响最大的是它们处理位于边界上的整数的舍入方式(例如4.5位于45的边界上)。请考虑以下代码片段和输出:

double val1 = 4.2;
double val2 = 4.5;
System.out.println("Math.rint(" + val1 + ")    = " + Math.rint(val1));
System.out.println("Math.round(" + val1 + ")   = " + Math.round(val1));
System.out.println("Math.rint(" + val2 + ")    = " + Math.rint(val2));
System.out.println("Math.round(" + val2 + ")   = " + Math.round(val2));
System.out.println("Math.rint(" + (val2 + 0.001d) + ")  = " + Math.rint(val2 + 0.001d));
System.out.println("Math.round(" + (val2 + 0.001d) + ") = " + Math.round(val2 + 0.001d));

输出:

Math.rint(4.2)    = 4.0
Math.round(4.2)   = 4
Math.rint(4.5)    = 4.0
Math.round(4.5)   = 5
Math.rint(5.5)    = 6.0
Math.round(5.5)   = 6
Math.rint(4.501)  = 5.0
Math.round(4.501) = 5

如您所见,Math.rint(4.5) 实际上将其转换为最近的偶数整数,而 Math.round(4.5) 则会向上舍入,并且这值得指出。但是,在所有其他情况下,它们都表现出我们所期望的相同的舍入规则。

这里有一篇有用的 Code Ranch 文章,简要比较了 Math.rint()Math.round()http://www.coderanch.com/t/239803/java-programmer-OCPJP/certification/Difference-rint-methods-Math-class


11
这里需要注意的是,.rint() 并不总是向下舍入。实际上它会在 .5 的情况下向最近的偶数整数舍入。比如 Math.rint(1.5),实际上会舍入到 2.0。 - Fleep
@Fleep 有没有任何数学上的理由将数字四舍五入为偶数? - Matthieu
2
@Matthieu 请查看 https://en.wikipedia.org/wiki/Rounding#Round_half_to_even - Fleep
3
谢谢@Fleep。总结一下:该方法对待正负值具有对称性,因此不会出现符号偏差。 - Matthieu
结论:roundrint都会将数字四舍五入到最接近的整数。当数字恰好处于两个整数中间时,前者会向上舍入(到正无穷),而后者会舍入为偶数。注意:通过使用rint进行偶数舍入,我们可以在计算一组数字的平均值时避免统计偏差。 - rosshjb

8

Math.rint()示例: 2.50位于2.00和3.00之间。 Math.rint()返回最接近的偶数double值。 Math.rint(2.50)返回2.0。

Math.round()示例: 2.50位于2.00和3.00之间。 Math.round()返回最接近的较高整数。 Math.round(2.50)返回3


4

有一种类型的返回值差异:

Math.round() 返回 longint
Math.rint() 返回 double

但关键的区别在于对0.5处数值的处理。

Math.round()9.5 <= x < 10.5 转换为 10
Math.rint()9.5 <= x <= 10.5 转换为 10.0

Math.round()10.5 <= x < 11.5 转换为 11
Math.rint()10.5 < x < 11.5 转换为 11.0

Math.round()11.5 <= x < 12.5 转换为 12
Math.rint()11.5 <= x <= 12.5 转换为 12.0

(注意不等式!) 因此,Math.round() 总是在中点(0.5)向上舍入:文档
相反,Math.rint() 偏向于中点最接近的偶数:文档

例如,尝试运行以下简单示例:

public class HelloWorld{
    public static void main(String []args){
        System.out.println("Math.round() of 9.5 is " + Math.round(9.5));
        System.out.println("Math.round() of 10.5 is " + Math.round(10.5));
        System.out.println("Math.round() of 11.5 is " + Math.round(11.5));
        System.out.println("Math.round() of 12.5 is " + Math.round(12.5));
        System.out.println("Math.rint() of 9.5 is " + Math.rint(9.5));
        System.out.println("Math.rint() of 10.5 is " + Math.rint(10.5));
        System.out.println("Math.rint() of 11.5 is " + Math.rint(11.5));
        System.out.println("Math.rint() of 12.5 is " + Math.rint(12.5));
    }
}

请注意,目前排名第一的答案错误的。我试图为他的帖子提出修改意见,但被拒绝了。因此根据拒绝评论,我将我的修改作为一个新答案发布。

这个逻辑同样适用于负数,简而言之,主要区别在于0.5小数部分。如果数字是x.5类型,则rint()更喜欢偶数double值。非常感谢Beast。 - Shubham Arya

4
当传入以.5结尾的参数、 signed 0NaNInfinity时,它们的行为会有所不同。 Math.round 接受doublefloat,但由于一些原因返回类型不同(分别是longint,这是能覆盖整个参数范围的最小类型)。 Math.rint 接受double并返回double。与Math.round相比,它更少“破坏”值,因为在几种情况下它不会改变值(见下文)。

此方法的行为遵循IEEE Standard 754第4节。这种取整有时被称为“四舍五入”,或者银行家舍入法。它最小化了由于始终朝一个方向舍入中点值而导致的舍入误差。

(来自C#中Jon Skeet的答案。 Math.Round在C#中的行为更类似于Java中的Math.rint,尽管可能很令人困惑。)
来自文档
static double rint(double a)

Returns the double value that is closest in value to the argument and is equal to a mathematical integer.

Returns the double value that is closest in value to the argument and is equal to a mathematical integer. If two double values that are mathematical integers are equally close, the result is the integer value that is even.

Special cases:

  • If the argument value is already equal to a mathematical integer, then the result is the same as the argument.

  • If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the argument.

...

static long round(double a)

...

static int round(float a)

Returns the closest int to the argument, with ties rounding up.

Special cases:

  • If the argument is NaN, the result is 0.
  • If the argument is negative infinity or any value less than or equal to the value of Integer.MIN_VALUE, the result is equal to the value of Integer.MIN_VALUE.
  • If the argument is positive infinity or any value greater than or equal to the value of Integer.MAX_VALUE, the result is equal to the value of Integer.MAX_VALUE.

您还可以通过RoundingMode更改Math.round的行为:

public enum RoundingMode
extends Enum<RoundingMode>

Specifies a rounding behavior for numerical operations capable of discarding precision. Each rounding mode indicates how the least significant returned digit of a rounded result is to be calculated. If fewer digits are returned than the digits needed to represent the exact numerical result, the discarded digits will be referred to as the discarded fraction regardless the digits' contribution to the value of the number. In other words, considered as a numerical value, the discarded fraction could have an absolute value greater than one.

Each rounding mode description includes a table listing how different two-digit decimal values would round to a one digit decimal value under the rounding mode in question. The result column in the tables could be gotten by creating a BigDecimal number with the specified value, forming a MathContext object with the proper settings (precision set to 1, and the roundingMode set to the rounding mode in question), and calling round on this number with the proper MathContext. A summary table showing the results of these rounding operations for all rounding modes appears below.

Result of rounding input to one digit with the given rounding

Input UP DOWN CEILING FLOOR HALF_UP HALF_DOWN HALF_EVEN UNNECESSARY
5.5 6 5 6 5 6 5 6 throw ArithmeticException
2.5 3 2 3 2 3 2 2 throw ArithmeticException
1.6 2 1 2 1 2 2 2 throw ArithmeticException
1.1 2 1 2 1 1 1 1 throw ArithmeticException
1.0 1 1 1 1 1 1 1 1
-1.0 -1 -1 -1 -1 -1 -1 -1 -1
-1.1 -2 -1 -1 -2 -1 -1 -1 throw ArithmeticException
-1.6 -2 -1 -1 -2 -2 -2 -2 throw ArithmeticException
-2.5 -3 -2 -2 -3 -3 -2 -2 throw ArithmeticException
-5.5 -6 -5 -5 -6 -6 -5 -6 throw ArithmeticException

3
差异在于 .5
Math.round()[10.5, 11.5[ 转换为 11。
Math.rint()]10.5, 11.5[ 转换为 11.0。
Math.round() 返回 long 或 int。
Math.rint() 返回 double。
因此可以说,Math.round() 更偏向于使用中点(0.5)来取较高的值。

1

对于正数:

如果小数部分在0(包括)和0.5(不包括)之间,则round()返回该数字的整数部分。

如果小数部分在0.5(包括)和1(不包括)之间,则round()返回该数字的整数部分+1。

但是在rint的情况下,

如果小数部分在0(包括)和0.5(包括)之间,则rint()返回该数字的整数部分。

如果小数部分在0.5(不包括)和1(不包括)之间,则round()返回该数字的整数部分+1。

对于负数:

两者的行为相同,即

如果小数部分在0(包括)和0.5(包括)之间,则返回该数字的整数部分。

如果小数部分在0.5(包括)和1(不包括)之间,则返回该数字的整数部分-1。

小数部分只是小数点后面的部分


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接