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

C 带无符号分子的有符号除法,c,embedded,signed,C,Embedded,Signed,我试图计算一个滚动平均值,并尝试获得和优化一点,我简化了计算,所以只有一个除法。当该值减小时,存在一个点,当前值降低到低于平均值。在这一点上,平均跳跃。我想这是因为除法是无符号的,分子的符号位被解释为一个巨大的无符号数。我只是不确定我需要在哪里施放unsigned,以确保这个问题不会再次出现 unsigned int AverageUsage; unsigned int TotalUsage; unsigned int incCount; AverageUsage = (TotalUs

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

unsigned int AverageUsage;
unsigned int TotalUsage;
unsigned int incCount;

    AverageUsage = (TotalUsage - AverageUsage)/++incCount + AverageUsage;
AverageUsage始终为正值,但当TotalUsage下降到AverageUsage以下时,我不确定该分区会有什么结果

    AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage;
将分子设置为signed,但我不确定如何进行除法

    AverageUsage =  (signed int)((signed int)(TotalUsage - AverageUsage)/++incCount) + AverageUsage;
应该有效(我可以保证这个完整操作的结果永远不会是负的),但我担心incCount达到“看起来”为负的值的情况

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

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

您有两种选择

使用浮点数学

我想你还是想这样做,得到一个合适的平均值

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

分子或分母是有符号还是无符号并不重要。没有无符号浮点。分母incCount将转换为浮点,并进行全浮点除法

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

如果出于某种原因,您希望保留整数除法,那么分子和分母必须是相同的有符号/无符号类型

分子/分母都有符号

incCount将转换为带符号的数字。如果它太大,那么它将看起来像一个负数,你的答案将是错误的。您必须测试此溢出

分子/分母都是无符号的


必须使分子无符号,并使用if()语句来处理两种情况:
TotalUsage
TotalUsage>AverageUsage
。这里incCount可以使用整数位的完整范围,因为它将被视为无符号数。

请注意,这当然不是标准平均值。标准平均数为:

Averageusage = TotalUsage / ++incCount
假设(理想情况下)incCount是一些有用的周期性递增值(如秒)

衰减平均值的实现方式通常更像:如果我翻译正确的话:

AverageUsage = TotalUsage / (incCount+1) + incCount/(incCount+1) * AverageUsage;
incCount++;

正如Himadri所提到的,这些操作可能应该用浮点运算来完成。

C二进制运算(包括除法)的一般规则是,操作数都将转换为相同的类型,即:
int
无符号int
long
无符号long
intmax\t
uintmax\u t
float
double
long double
。如果两个操作数都属于该列表中的类型,则它们都将转换为后面的操作数。如果两者都不是,它们都将转换为
int

在你的例子中:

AverageUsage = (signed int)(TotalUsage - AverageUsage)/++incCount + AverageUsage
如果
incCount
unsigned int
,则您的强制转换无效——减法将转换为signed int,然后右返回unsigned int,并执行无符号除法。如果您想要签名分区,则需要:

AverageUsage = (int)(TotalUsage - AverageUsage)/(int)++incCount + AverageUsage
正如您所注意到的,如果incCount超过INT_MAX,可能会给您带来麻烦


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

如果它对TotalUsage 如果TotalUsagelong
unsigned long
double
都是合适的

即使使用强制转换,如果TotalUsage 最终的结论是TotalUsage 我的建议通常是对要执行算术的变量始终使用有符号类型。这是因为混合有符号/无符号算术的语言语义有些晦涩,容易被误解,而且中间操作可能会生成负值。即使变量的负值在语义上没有意义的情况下,我仍然主张在所有情况下使用有符号类型,在这些情况下,此类类型的正范围仍然足以避免溢出,并且不足以避免溢出。尽可能使用更大的类型,而不是求助于大小相同的无符号类型。此外,无符号类型上的算术运算必需的
new_output = alpha * previous_output + (1-alpha)*new_input;
previous_output = new_output;