为什么Math.Round/Floor/Ceiling不返回long或int类型?

25

每次我使用Math.Round/Floor/Ceiling函数时,我总是将结果强制转换为int(如果必要的话也可能是long)。它们返回double,但为什么呢?毕竟最终结果总是一个整数。

4个回答

32

计算结果可能无法用int(或long)类型来存储。double类型的范围要大得多。

double类型的大约范围:±5.0 × 10−324 到 ±1.7 × 10308

(来源)


他们在问题中说了很长时间。 - bwawok
3
重点仍然是一样的。一个“double”可以比9223372036854775807更大。 - dan04
1
我想这应该是原因,但只是想确认一下。显然,对于大多数应用程序来说,将四舍五入为比long更大的整数是罕见的,但微软仍然不得不实现它以在数学上有意义。谢谢! - TheCloudlessSky
2
@dan04: 确实如此,但只有小于2^52的双精度数才能具有非零小数部分,因此该函数通常仅在已知数字的动态范围低于该值的情况下才有用。我认为更大的问题是,希望将浮点类型转换为舍入整数类型的代码可能同样希望得到Int32Int64,而没有明智的方法来使用重载来传达这一点。Java重载了round(double)以返回long,但重载了round(float)以返回int,有趣的是,在long超过2^31时调用round将会钉住它... - supercat
将一个 long 值强制转换为最大的 int 值,并在其他大于 16777216 的 long 值上调用它将产生舍入到最接近的 float 的结果。 - supercat

8

我同意Mark的答案,即结果可能不适合long类型,但您可能会想: 如果C#有一个更长的long类型会怎样呢?好吧,这就是Python中使用任意长度整数的情况:

>>> round(1.23e45)
1229999999999999973814869011019624571608236032

大部分数字都是浮点舍入误差中的“噪声”。在C#中,Round/Floor/Ceiling返回double的原因可能是为了避免假精度的幻觉。
另一种解释是,.NET的Math模块使用用C编写的代码,其中floorceil返回浮点类型。

2
除了范围参数之外,这些答案都没有解决一个对我来说很重要的问题,即当您真正需要精确整数时返回浮点数的根本问题。我认为,计算出的浮点数可能会因为小的舍入误差而比所需整数小或大,因此强制转换操作可能会创建一个偏离一个的错误。我认为,您需要将floor()的双精度结果应用于整数(而不是double)四舍五入函数,而不是进行强制转换。否则,您需要编写自己的代码。C库版本的floor()ceil()非常慢。

这是真的吗,还是我遗漏了什么?IEEE浮点标准中关于整数的精确表示有一些内容,但我不确定这是否使得转换安全。

我宁愿在函数中进行范围检查(如果需要避免溢出)并返回long类型。对于我的私人代码,我可以跳过范围检查。我一直在这样做:

long int_floor(double x)
{
    double remainder;
    long truncate;
    truncate = (long) x;        // rounds down if + x, up if negative x
    remainder = x - truncate;   // normally + for + x, - for - x
    //....Adjust down (toward -infinity) for negative x, negative remainder
    if (remainder < 0 && x < 0)
        return truncate - 1;
    else
        return truncate;
}

ceil()round()有相应的函数可以处理正负数,但是方法不同。


如果想将浮点数映射到需要 Int32Int64 的代码中,直接使用四舍五入或向负无穷大舍入的方法进行映射会很有帮助。 - supercat
浮点数的四舍五入操作不能产生当前不存在的舍入误差,因为具有小数部分的最大数字上方的整数是可以精确表示的。 - supercat

-2

文档中没有给出我能找到的原因。我最好的猜测是,如果您正在使用双精度浮点数,则很可能希望对双精度浮点数进行的任何操作都返回双精度浮点数。将其四舍五入以转换为int被语言设计者认为比保留为double更不常见。

您可以编写自己的方法,以大约2行代码将其转换为int,而且比在堆栈溢出上发布问题要少得多...


2
当然,编写自己的代码很容易,但Mark的答案提供了深入的见解。StackOverflow并不仅仅关注“如何”,我也喜欢它的“为什么” :) - si618
3
我知道如何,但我想知道为什么。你的回答甚至没有意义。 - TheCloudlessSky

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