在How does DoubleUtil.DoubleToInt(double val) work?中我们了解到.NET Framework有一种舍入浮点值的特殊方法:
public static int DoubleToInt(double val)
{
return (0 < val) ? (int)(val + 0.5) : (int)(val - 0.5);
}
为什么他们不只是使用(int)Math.Round(val)
?
或者:如果这是优越的,为什么Math.Round
没有这样定义?必须有一些权衡。
答案 0 :(得分:4)
Math.Round
会导致创建具有所需精确值的double
,然后需要将其转换为int
。这里的代码避免了double
的创建。它还允许省略错误处理,并将与其他类型的舍入模式或数字相关的代码舍入到。
答案 1 :(得分:3)
它们在值上具有不同的行为,其中小数部分为1/2。根据{{3}}:
如果a的小数分量在两个整数之间,其中一个是偶数,另一个是奇数,则返回偶数。
因此,如果val == 0.5
,则为Math.Round(val) == 0.0
,而此DoubleToInt
会给(int)(0.5+0.5) == 1
。换句话说,DoubleToInt
距离零点1/2(与标准C round
函数一样)。
此处也存在不太理想的行为:如果val
实际上是 0.5之前的double
(即0.49999999999999994),那么,取决于C#如何处理中间精度,它实际上可能给1(因为val + 0.5
不能由double
表示,并且可以舍入为1)。事实上,这在Java 6(及更早版本)中是Math.Round
。
答案 2 :(得分:1)
我可以看到这是一种优化,因为要从Round
获得相同的行为,您需要使用MidpointRounding.AwayFromZero
选项。从reference source开始,这是通过以下方式实现的:
private static unsafe double InternalRound(double value, int digits, MidpointRounding mode) {
if (Abs(value) < doubleRoundLimit) {
Double power10 = roundPower10Double[digits];
value *= power10;
if (mode == MidpointRounding.AwayFromZero) {
double fraction = SplitFractionDouble(&value);
if (Abs(fraction) >= 0.5d) {
value += Sign(fraction);
}
}
else {
// On X86 this can be inlined to just a few instructions
value = Round(value);
}
value /= power10;
}
return value;
}
我只能猜测实用程序方法的作者做了一些性能比较。