C# System.Math.Round-四舍五入到零位,并将与四舍五入相比的结果除以一个或多个数字
在我身边的一次误解之后,在阅读问题的答案时C# System.Math.Round-四舍五入到零位,并将与四舍五入相比的结果除以一个或多个数字,c#,math,rounding,C#,Math,Rounding,在我身边的一次误解之后,在阅读问题的答案时 参考问题概述: 问:想知道:如何在0.05步内将金额四舍五入到最接近的值 答:提供的解决方案是将数值乘以20,然后四舍五入,至少除以20 。。。我提出了一个更一般的问题: 这两种方法之间是否存在任何实际优势/劣势: (I) var rValue = Math.Round(value * 10.0m , 0) / 10.0m; (II) var rValue = Math.Round(value, 1); (I) var rValue =
参考问题概述: 问:想知道:如何在0.05步内将金额四舍五入到最接近的值 答:提供的解决方案是将数值乘以20,然后四舍五入,至少除以20
。。。我提出了一个更一般的问题: 这两种方法之间是否存在任何实际优势/劣势:
(I) var rValue = Math.Round(value * 10.0m , 0) / 10.0m;
(II) var rValue = Math.Round(value, 1);
(I) var rValue = Math.Round(value * 10.0m , 0) / 10.0m;
(II) var rValue = Math.Round(value, 1);
到目前为止我所做的: 起初,我看了看地图,但找不到任何线索。我还查看了,看看是否有任何不同的执行分支,但到目前为止,它只提供了:
public static Decimal Round(Decimal d, int decimals)
{
FCallRound (ref d, decimals);
return d;
}
和fc全部如下:
private static extern void FCallRound(ref Decimal d, int decimals);
不幸的是,我没有找到fcall
的一些代码
在那之后,我想更实际一些,想看看在舍入到0位或1..n位和之间是否有任何性能差异 首先,我将介绍这三个函数调用:
(1) var rValue = Math.Round(value, 0);
(2) var rValue = Math.Round(value, 1);
(3) var rValue = Math.Round(value, 12);
这向我表明,在1'000'000次迭代中,所有三次执行的都是安静的相等(~70ms)。而且在执行上似乎没有什么不同
但为了检查是否有任何意外,我写了以下几行:
(1) var rValue = Math.Round(value, 1);
(2) var rValue = Math.Round(value * 10.0m, 0);
(3) var rValue = Math.Round(value * 10.0m, 0) / 10.0m;
正如预期的那样,每次乘法都会增加时间(每次约70毫秒)
因此,正如中所预期的那样,舍入和除法(而不是舍入到所需的小数位数)并没有性能优势
重复我的问题: 这两种方法之间是否存在任何实际优势/劣势:
(I) var rValue = Math.Round(value * 10.0m , 0) / 10.0m;
(II) var rValue = Math.Round(value, 1);
(I) var rValue = Math.Round(value * 10.0m , 0) / 10.0m;
(II) var rValue = Math.Round(value, 1);
对更新问题的简短(er)回答
实际上,您可以在中看到当前FCallRound
实现的代码。如果你走来走去,你可能会看到它被映射到了上面,反过来又把大部分逻辑委托给了它。您可以在链接中看到完整的代码,但关键部分是:
iScale = pdecIn->u.u.scale - cDecimals;
do {
ulSticky |= ulRem;
if (iScale > POWER10_MAX)
ulPwr = ulTenToNine;
else
ulPwr = rgulPower10[iScale];
ulRem = Div96By32(rgulNum, ulPwr);
iScale -= 9;
} while (iScale > 0);
其中常量定义为
#define POWER10_MAX 9
static const ULONG ulTenToNine = 1000000000U;
static ULONG rgulPower10[POWER10_MAX+1] = {1, 10, 100, 1000, 10000, 100000, 1000000,
10000000, 100000000, 1000000000};
因此,这段代码的作用是找出当前值应该移位多少个十进制位置,然后分批进行除法,直到10^9
(而10^9
是10的最大幂,适合32位)。这意味着性能差异可能有两个潜在来源:
decimal value = 92233720368.547758m
尾数是多少≈ <代码>2^63/100。那么Math.Round(value,4)
将比Math.Round(value*10000,0)
快,即使您不考虑计算value*10000的时间(
)
但我认为,在任何实际使用中,您都不会注意到任何显著的差异
原始长答案 我认为你没有抓住问题的重点。主要问题是Feii Momo希望40.23四舍五入到40.25。这是一个精度不等于小数位数的整数!使用舍入到指定的小数位数,您将得到40.23(>=2位)或40.2(0)(1位)。乘法和除法技巧是一个简单的技巧,可以在子位数精度上进行舍入(但它仅在“子位数”是2的负幂时有效,例如0.5或0.25/0.5/0.75等)。此外,我还不知道还有什么简单的方法不使用这种乘轮除法 是的,不管怎样,当你进行乘除,是否进行乘除并不重要
var rValue = Math.Round(value * 20.0m, 0) / 20.0m;
或
因为轮和除法都独立于它们的第二个参数而占用相同的时间。请注意,在第二个示例中,您没有回避第一个示例中的任何基本步骤!所以这不是真的
为什么取整和除法比取整到指定的小数更容易
一个比另一个好几乎完全是主观的事情。(我可以想到一些边缘案例,第二个不会失败,而第一个会失败,但只要我们讨论原始问题中提到的任何实际金额,它们就不相关。)
综上所述:
我想你只是误读了。“在我看来,四舍五入到一个整数,然后再向下转换是比较容易的。”这并不意味着计算机更容易执行,而是意味着有问题的人更容易理解。@hvd这是一个正确的观点。我不是这样想的。考虑一下写一个最接近分数的通用循环-如果你通过了0.05:
RoundTo(v,0.05)
?@Chris再次感谢你。我试图编辑我的问题。你能检查一下吗?@MartinBackasch:好多了。我现在有投票权了。:)我理解问题的重点,但我可能表达的关切不够清楚。这与整个计算无关。这只是“Math.Round(value,0)”的一部分。通常我是通过乘以2并将其四舍五入为1来解决这个问题的,而不是乘以20并将其四舍五入为零的小数位数,这将导致相同的结果。@MartinBackasch,1。你读过我的“总结”部分了吗?2.我相信你对《谜》所说的话的理解是错误的。这不是不同取整位置的矛盾。这是乘圆除t的矛盾