gpt4 book ai didi

c# - System.Math.Round - 四舍五入到零位和除法与四舍五入到一个或多个数字

转载 作者:行者123 更新时间:2023-11-30 23:06:26 24 4
gpt4 key购买 nike

经过我这边的误解,同时阅读问题的答案How to get numbers to a specific decimal place ...


引用问题摘要:

问: Feii Momo想知道:如何在 0.05 步内将金额四舍五入到最接近的值。

答:Enigmativity提供的解决方案就是把值乘以20四舍五入至少除以20

Math.Round(value * 20.0m, 0) / 20.0m

...我提出了一个更通用的问题:

Are there any practical advantages/disadvantages between these two approaches:

(I)  var rValue = Math.Round(value * 10.0m , 0) / 10.0m;  
(II) var rValue = Math.Round(value, 1);

到目前为止我做了什么:

起初我看着Docs - System.Math.Round ,但我找不到任何提示。我也看看Reference Source - Decimal Round查看是否有任何不同的执行分支,但到目前为止它只出现:

public static Decimal Round(Decimal d, int decimals)
{
FCallRound (ref d, decimals);
return d;
}

FCallRound作为:

private static extern void FCallRound(ref Decimal d, int decimals);

很遗憾,我没有找到FCallRound 的代码。


在那之后,我想更实际一点,想看看舍入到 0 位或 1..n 位和 "raced the horses" 之间是否存在任何性能差异。 .

起初我run这三个函数调用:

(1) var rValue = Math.Round(value, 0);
(2) var rValue = Math.Round(value, 1);
(3) var rValue = Math.Round(value, 12);

这向我表明,对于 1'000'000 次迭代,所有三个都执行安静相等(~70 毫秒)。执行起来似乎没有区别。

但只是为了检查是否有意外惊喜,我 compared这些行:

(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 毫秒)。

正如中预期的那样四舍五入和除法而不是四舍五入到所需的小数位数没有性能优势。


所以重复我的问题:

Are there any practical advantages/disadvantages between these two approaches:

(I)  var rValue = Math.Round(value * 10.0m , 0) / 10.0m;  
(II) var rValue = Math.Round(value, 1);

最佳答案

更新问题的简短(呃)回答

其实可以在CoreCLR中看到当前FCallRound实现的代码.如果你穿过ecalllist.h#L784 ,您可能会看到它映射到 COMDecimal::DoRound这又将大部分逻辑委托(delegate)给 VarDecRound .您可以在链接中查看完整代码,但关键部分是:

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 是适合 32 位的 10 的最大幂)。这意味着性能差异可能有两个潜在来源:

  1. 您四舍五入到超过 9 位有效数字,因此如果您先乘法,循环将运行更多次
  2. Div96By32如果乘法后尾数有更多的非零 32 位字,则可能工作得更慢。

所以是的,当带有乘法的代码运行速度变慢时,您可以创建一个人工示例。例如,如果您以

开头,则可以利用差异 #2
decimal value = 92233720368.547758m

尾数为 ≈ 2^63/100。那么 Math.Round(value, 4) 将比 Math.Round(value*10000, 0) 更快,即使您不考虑计算时间 值*10000 ( see online )。

我仍然认为在任何现实生活中您都不会注意到任何显着差异。


原始长答案

我认为您错过了所引用问题的全部要点。主要问题是飞衣陌陌希望将 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;

var rValue = Math.Round(value * 2.0m, 1) / 2.0m;

因为 Round 和除法都花费相同的时间,而与它们的第二个参数无关。请注意,在您的第二个示例中,您没有避免第一个示例的任何基本步骤!所以不是真的

Why should it be easier to round and divide instead of round to a specified fractional digit?

一个人是否比另一个人更好几乎是纯粹主观的事情。 (我可以想到一些边缘情况,当第二个不会失败而第一个会失败,但只要我们谈论原始问题中提到的任何实际金额,它们就无关紧要。)

总结一下:

  1. 你能避免乘法和除法而只使用 Math.Round 吗?很可能没有
  2. 你能乘以和除以一个不能被 10 整除的数吗?这会有什么不同吗?是的你可以。不,几乎可以肯定不会有任何区别。

关于c# - System.Math.Round - 四舍五入到零位和除法与四舍五入到一个或多个数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48216487/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com