我正在尝试计算滚动平均值,并试图获得并优化一点,我简化了计算,因此只有一个除法。当值减小时,存在当前值降低到小于平均值的点。此时平均跳跃。我想这是因为除法是无符号的,我的分子符号位被解释为一个大的无符号数。我只是不确定我需要在哪里投贴无符号以确保此问题不再出现。
unsigned int AverageUsage;
unsigned int TotalUsage;
unsigned int incCount;
AverageUsage = (TotalUsage - AverageUsage)/++incCount + AverageUsage;
AverageUsage将始终为正,但当TotalUsage低于AverageUsage时,我不确定该部门会有什么期望
AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage;
将分子设置为有符号,但我不确定除法是如何发生的。
AverageUsage = (signed int)((signed int)(TotalUsage - AverageUsage)/++incCount) + AverageUsage;
应该有效(我可以保证这个完整操作的结果永远不会是负面的),但是我担心incCount达到'看起来'为负值的情况。
希望有一个简单的解决方案:
谢谢!
答案 0 :(得分:5)
C二进制操作(包括除法)的一般规则是操作数将被转换为相同的类型,即:int
,unsigned int
,long
, unsigned long
,intmax_t
,uintmax_t
,float
,double
,long double
。如果两个操作数都是该列表中的类型,则它们都将转换为后一个操作数。如果两者都不是,则它们都将被转换为int
所以在你的例子中:
AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage
如果incCount
是unsigned int
,那么你的演员表没有效果 - 减法将转换为signed int,然后再回到unisgned int,并且将完成无符号除法。如果你想要一个签名的部门,你需要:
AverageUsage = (int)(TotalUsage - AverageUsage)/(int)++incCount + AverageUsage
如果你注意到,如果incCount超过INT_MAX,你可能会遇到麻烦。
通常,除法的处理器指令仅指定一种类型,用于两个操作数。如果有一个特殊的除法类型的除法指令,它通常用于较大的(双倍宽度)红利,而不是不同的符号。
答案 1 :(得分:4)
您有2个选项。
使用浮点数学
我认为你想要这样做才能获得适当的平均值。
没有混合浮点/整数除法。因此,分子和分母都将转换为浮点数。
分子或分母是签名还是无符号然后无关紧要。没有无符号浮点数。分母incCount将转换为浮点,并且将完成全浮点除法。
使用整数除法并处理特殊情况
如果由于某种原因你想要保持整数除法,那么分子和分母都必须是相同的有符号/无符号类型。
分子/分母均已签名
incCount将转换为签名号码。如果它太大,那么它看起来像一个负数,你的答案就错了。你必须测试这个溢出。
Numerator / Denominator均未签名
您必须使分子无符号并使用if()语句来处理这两种情况:TotalUsage < AverageUsage
和TotalUsage > AverageUsage
。这里incCount可以使用整个范围的整数位,因为它将被视为无符号数。
答案 2 :(得分:1)
当然注意,这不是标准平均值。标准平均值为:
Averageusage = TotalUsage / ++incCount
假设(理想情况下)incCount是一些有用的周期性增加值(如秒)。
衰减平均值通常更像是:http://donlehmanjr.com/Science/03%20Decay%20Ave/032.htm,如果我已正确翻译,则为:
AverageUsage = TotalUsage / (incCount+1) + incCount/(incCount+1) * AverageUsage;
incCount++;
正如Himadri所提到的,这些应该可以用浮点运算来完成。
答案 3 :(得分:0)
如果可以预见且对TotalUsage有效且&lt; AverageUsage,那么这些变量是无符号类型是完全不合适的。 TotalUsage&lt; AverageUsage意味着AverageUsage可能是负数(如果TotalUsage&lt; AverageUsage,那将是结果。如果'平均'数据永远不是负数,那么TotalUsage&lt; AverageUsage在数学上是不可能的。
如果TotalUsage&lt; AverageUsage无效,那么它为true表示代码中有错误或算术溢出。你可以用断言来防范这种可能性;也许一个实现为在发布版本中删除的宏。如果断言发生,则输入数据无效或发生溢出,在后一种情况下,数据类型太小,并且long long
,unsigned long long
或double
是合适的。
即使进行了投射,如果TotalUsage&lt; AverageUsage为true,则表达式的结果为算术负数,但最终分配给无符号类型,因此结果仍然不正确。
最终的结论是TotalUsage&lt; AverageUsage永远不会成立,或者您的数据类型不合适。解决方案几乎肯定不是任何类型的演员。
我的建议通常是总是对要执行算术运算的变量使用带符号的类型。这是因为混合有符号/无符号算术的语言语义有些晦涩且容易被误解,并且因为中间操作可能会产生负值。即使变量的负值在语义上没有意义,我仍然主张在所有情况下使用有符号类型,其中这种类型的正范围仍然足以避免溢出,并且它还不够。尽可能使用更大的类型,而不是使用相同大小的无符号类型。此外,在需要对无符号类型进行算术运算的情况下,所有操作数都应该是无符号的(包括文字),并且不应该导致中间操作或溢出。
答案 4 :(得分:0)
你真的/需要/滚动平均,还是可以使用其他低通滤波器?单极(有时称为“alpha”)滤波器可能适合您:
new_output = alpha * previous_output + (1-alpha)*new_input;
previous_output = new_output;
其中alpha
介于0和0.9999之间....
较近的alpha
为1,过滤器的“较慢”为
您可以在浮点中轻松地执行此操作,也可以非常简单地在整数中执行此操作。