带无符号分子的带符号除法

时间:2011-05-27 20:22:03

标签: c embedded signed

我正在尝试计算滚动平均值,并试图获得并优化一点,我简化了计算,因此只有一个除法。当值减小时,存在当前值降低到小于平均值的点。此时平均跳跃。我想这是因为除法是无符号的,我的分子符号位被解释为一个大的无符号数。我只是不确定我需要在哪里投贴无符号以确保此问题不再出现。

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达到'看起来'为负值的情况。

希望有一个简单的解决方案:

  • 不需要if语句
  • 不需要QWORDs

谢谢!

5 个答案:

答案 0 :(得分:5)

C二进制操作(包括除法)的一般规则是操作数将被转换为相同的类型,即:intunsigned intlongunsigned longintmax_tuintmax_tfloatdoublelong double。如果两个操作数都是该列表中的类型,则它们都将转换为后一个操作数。如果两者都不是,则它们都将被转换为int

所以在你的例子中:

AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage

如果incCountunsigned int,那么你的演员表没有效果 - 减法将转换为signed int,然后再回到unisgned int,并且将完成无符号除法。如果你想要一个签名的部门,你需要:

AverageUsage = (int)(TotalUsage - AverageUsage)/(int)++incCount + AverageUsage

如果你注意到,如果incCount超过INT_MAX,你可能会遇到麻烦。

通常,除法的处理器指令仅指定一种类型,用于两个操作数。如果有一个特殊的除法类型的除法指令,它通常用于较大的(双倍宽度)红利,而不是不同的符号。

答案 1 :(得分:4)

您有2个选项。

使用浮点数学

我认为你想要这样做才能获得适当的平均值。

没有混合浮点/整数除法。因此,分子和分母都将转换为浮点数。

分子或分母是签名还是无符号然后无关紧要。没有无符号浮点数。分母incCount将转换为浮点,并且将完成全浮点除法。

使用整数除法并处理特殊情况

如果由于某种原因你想要保持整数除法,那么分子和分母都必须是相同的有符号/无符号类型。

分子/分母均已签名

incCount将转换为签名号码。如果它太大,那么它看起来像一个负数,你的答案就错了。你必须测试这个溢出。

Numerator / Denominator均未签名

您必须使分子无符号并使用if()语句来处理这两种情况:TotalUsage < AverageUsageTotalUsage > 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 longunsigned long longdouble是合适的。

即使进行了投射,如果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,过滤器的“较慢”为

您可以在浮点中轻松地执行此操作,也可以非常简单地在整数中执行此操作。