为什么Math.round返回long类型,而Math.floor返回double类型?

43

为什么会不一致呢?


2
+1 很好的观察。好奇的人想知道 :) - BoltClock
6
鉴于早期基础库的拼凑方式,很可能是由于许多历史遗留依赖项而无法改变的历史意外。如果是这样,那么对于这个问题的答案也很可能会随着时间的推移而失落。 - msw
4个回答

16

没有矛盾:这些方法只是根据不同的规范来设计。

因此,按设计round舍入为long,而rint舍入为double。自JDK 1.0以来一直如此。

JDK 1.2引入了其他一些方法(例如toRadianstoDegrees),1.5引入了更多方法(例如log10ulpsignum等),1.6又加入了更多方法(例如copySigngetExponentnextUp等)(请在文档中查找Since:元数据);但是roundrint自一开始就一直保持现在的方式。

可以说,也许不是long rounddouble rint,而是将它们命名为double roundlong rlong更“一致”,但这是有争议的。尽管如此,如果您坚持在范畴上称之为“不一致”,那么原因可能令人不满意,就是“因为这是不可避免的”。

这里摘自《Effective Java第二版,条款40:小心设计方法签名》:

  

当你不确定时,请参考Java库API以获得指导。虽然存在很多不一致性 - 鉴于这些库的规模和范围,这是不可避免的 - 但也存在相当一致性。

相关问题

  • 最令人惊讶的最小惊讶原则违反

  • 12
    这个论点是无效的。如果他们规定floor()应该返回一个double,而ceil()应该返回一个int,那么这是否“一致”呢? - NullUserException
    6
    @NullUserException:floorceil密切相关。还有roundrint。我不知道你还想要什么。我试图客观地回答这个问题,进一步的推测似乎是假设性的和/或主观的。 - polygenelubricants
    2
    还不错...看起来.rint()方法是后来添加的,以解决不一致性问题。 - NullUserException
    4
    我以前从未听说过 Math.rint()。谢谢您的解释。 我认为 rint 是一个愚蠢的方法名。 - Leo Jay
    1
    @LeoJay:如果Math.rint()Math.rlong()分别返回intlong,那么当给定一个double时,Math.round()返回long,而给定任何其他原始类型时返回int,这样做会更有意义。 - supercat
    显示剩余2条评论

    7
    floor被选择是为了与math.h中的标准c例程匹配(另一个答案中提到的rint也在该库中,返回一个double,就像Java一样)。

    但是,在那个时候,round不是c的标准函数(在C89中没有提到它 - c标识符和标准;c99确实定义了round并返回一个double,就像你期望的那样)。语言设计者“借用”想法是很正常的,所以也许它来自其他语言?Fortran 77没有这个名称的函数,我不确定那时会使用什么作为参考。也许是vb-它确实有Round,但对于这个理论来说不幸的是,它返回一个double(php也是如此)。有趣的是,Perl故意避免定义round

    [更新:嗯。看起来Smalltalk返回整数。我不太了解Smalltalk是否正确和/或通用,方法称为rounded,但它可能是源。Smalltalk在某些方面确实影响了Java(尽管更多是概念上而不是细节上)。]

    如果不是Smalltalk,那么我们只能假设有人选择不当(考虑到Java中可能存在的隐式转换,似乎返回一个double会更有用,因为这样可以在转换类型和进行浮点计算时使用)。

    换句话说:Java和C共同使用的函数往往与当时的C库标准一致;其他函数似乎是任意的,但这个特定的问题可能来自Smalltalk。


    1

    我同意,Math.round(double) 返回 long 是有点奇怪的。如果将大的 double 值强制转换为 long(这是 Math.round 隐式执行的操作),则会返回 Long.MAX_VALUE。另一种选择是使用 Math.rint() 以避免这种情况。然而,Math.rint() 具有一种有点奇怪的舍入行为:平局按偶数整数四舍五入,即 4.5 被舍入为 4.0,但 5.5 被舍入为 6.0)。另一种选择是使用 Math.floor(x+0.5)。但请注意,1.5 被舍入为 2,而 -1.5 被舍入为 -1,而不是 -2。还有一种选择是使用 Math.round,但仅当数字在 Long.MIN_VALUE 和 Long.MAX_VALUE 之间时才使用。此范围外的双精度浮点值本质上是整数。

    遗憾的是,我们不知道为什么Math.round()返回long。有人做出了这个决定,他可能从未接受采访告诉我们原因。我的猜测是,Math.round被设计为提供更好的方式(即四舍五入)将双精度转换为长整型。


    0

    和这里的其他人一样,我也不知道答案,但想着有人可能会觉得这个有用。我注意到如果你想将 double 四舍五入为 int 而不使用强制转换,可以同时使用两个 round 实现 long round(double)int round(float)

    double d = something;
    int i = Math.round(Math.round(d));
    

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