Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# System.Math.Round-四舍五入到零位,并将与四舍五入相比的结果除以一个或多个数字_C#_Math_Rounding - Fatal编程技术网

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位)。这意味着性能差异可能有两个潜在来源:

  • 您将舍入到9个有效数字以上,因此如果您先乘法,循环将运行更多次
  • 如果在乘法后尾数有更多的非零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;
    

    因为轮和除法都独立于它们的第二个参数而占用相同的时间。请注意,在第二个示例中,您没有回避第一个示例中的任何基本步骤!所以这不是真的

    为什么取整和除法比取整到指定的小数更容易

    一个比另一个好几乎完全是主观的事情。(我可以想到一些边缘案例,第二个不会失败,而第一个会失败,但只要我们讨论原始问题中提到的任何实际金额,它们就不相关。)

    综上所述:

  • 你能避免乘法和除法,只使用数学吗?很可能没有
  • 你能用一个不能被10整除的数字乘和除吗?这会有什么不同吗?是的,你可以。不,几乎可以肯定不会有什么不同
    我想你只是误读了。“在我看来,四舍五入到一个整数,然后再向下转换是比较容易的。”这并不意味着计算机更容易执行,而是意味着有问题的人更容易理解。@hvd这是一个正确的观点。我不是这样想的。考虑一下写一个最接近分数的通用循环-如果你通过了0.05:
    RoundTo(v,0.05)
    ?@Chris再次感谢你。我试图编辑我的问题。你能检查一下吗?@MartinBackasch:好多了。我现在有投票权了。:)我理解问题的重点,但我可能表达的关切不够清楚。这与整个计算无关。这只是“Math.Round(value,0)”的一部分。通常我是通过乘以2并将其四舍五入为1来解决这个问题的,而不是乘以20并将其四舍五入为零的小数位数,这将导致相同的结果。@MartinBackasch,1。你读过我的“总结”部分了吗?2.我相信你对《谜》所说的话的理解是错误的。这不是不同取整位置的矛盾。这是乘圆除t的矛盾