为啥 Math.floor 返回一个双精度值?
Posted
技术标签:
【中文标题】为啥 Math.floor 返回一个双精度值?【英文标题】:Why does Math.floor return a double?为什么 Math.floor 返回一个双精度值? 【发布时间】:2010-10-05 10:40:05 【问题描述】:官方 Javadoc says Math.floor()
返回一个“等于数学整数”的 double
,但是为什么不应该返回一个 int
?
【问题讨论】:
【参考方案1】:根据同一个Javadoc:
如果参数是NaN
或无穷大或正零或负零,则结果与参数相同。不能用int
做到这一点。
最大的double
值也大于最大的int
,所以它必须是long
。
【讨论】:
似乎与 Math.Round 函数不一致,后者返回 int/long 并以不同的方式处理特殊情况。 注意 Javadoc 说它返回 " 最大(最接近正无穷大)*浮点值* 小于或等于参数并且等于到一个数学整数”。给定一个值 x > 2^53,它与截断小数部分的值不同。它可能比那个小很多。 @zod 也许他们认为人们只要愿意就可以做到(int) myFloatVar
。【参考方案2】:
这是为了精确。双精度数据类型有一个 53 位尾数。除其他外,这意味着双精度可以表示高达 2^53 的所有整数而不会丢失精度。
如果您将如此大的数字存储在一个整数中,您将得到溢出。整数只有 32 位。
将整数作为双精度返回是正确的做法,因为它提供了比整数更广泛的有用数字范围。
【讨论】:
当然,它可以返回一个 long 来处理这样的值。不过,您仍然需要弄清楚如何处理大于 2^63 的双打。 @Jon,是的,但这会导致性能影响(我知道的任何指令集中都没有从 long 到 double 的转换指令)。我想知道 Math.floor 首先对双打 > 2^53 做了什么。有些结果无法表示。 但是,也出现在官方 javadoc 中的伪惯用形式 (int)Math.floor(foo) 是不安全的,因为结果可能不适合 int,对吗?再说一次,这是一种使用 Math.floor 的安全形式,因为结果可能不适合 long?【参考方案3】:其他人已经告诉你原因,我将告诉你如何正确舍入,因为你想这样做。如果您只打算使用正数,那么您可以使用以下语句:
int a=(int) 1.5;
但是,(int) 总是向 0 舍入。因此,如果你想做一个负数:
int a=(int) -1.5; //Equal to -1
就我而言,我不想这样做。我使用以下代码进行舍入,它似乎很好地处理了所有边缘情况:
private static long floor(double a)
return (int) Math.floor(a);
【讨论】:
为什么不使用(int) Math.floor(a)
?它可能更有效而且更短。
@Solomon Ucko 而不是(int) Math.floor(a)
,如果a 是肯定的,你可以简单地写(int) a
。【参考方案4】:
如果你给它一个比最大的 int 或 long 大的两倍,你希望它返回什么?
(诚然,如果它大于最大的 long 精度无论如何都会很低 - 它可能不是最接近的理论整数 - 但即便如此......)
【讨论】:
【参考方案5】:正如Java中有整数和浮点除法一样,也有整数和浮点数的取数方式:
double f = Math.floor(x);
或
int k = (int) x;
但您始终需要小心使用具有有限精度算术的下限:您对 x 的计算可能会产生类似 1.99999999 的结果,这两种形式都将下限为 1,而不是 2。有许多算法需要解决这个限制,以避免为某些输入值产生错误的结果。
【讨论】:
【参考方案6】:这样误差和其他非整数值可以通过一系列计算正确级联。
例如,如果您将 Not a Number (NaN) 输入到 Math.floor,它会传递它。
如果它返回整数,则无法传递这些状态或错误,并且您可能会从早期的计算中得到错误的结果,这些结果看起来不错,但在进一步处理后却是错误的。
【讨论】:
以上是关于为啥 Math.floor 返回一个双精度值?的主要内容,如果未能解决你的问题,请参考以下文章