ints的最快c算法

ints的最快c算法,c,math,binary,overflow,C,Math,Binary,Overflow,我正在写一个c程序。我有一个无符号整数(16位),它的值在任何时候都可以是任何值,我有一个有符号字符(8位),它的值在任何时候都可以是任何值,在数据类型的明显限制内。我需要将有符号字符添加到无符号整数,结果是无符号整数,如果值溢出超过0xFFFF或低于0x00,我需要结果等于限制(0x00或0xFFFF)。我想知道做这件事最快的方法是什么?我的方法如下所示,但它使用长数据类型,因此使用长二进制算法,所以我猜有一种更快的方法 long i; unsigned int result; i = so

我正在写一个c程序。我有一个无符号整数(16位),它的值在任何时候都可以是任何值,我有一个有符号字符(8位),它的值在任何时候都可以是任何值,在数据类型的明显限制内。我需要将有符号字符添加到无符号整数,结果是无符号整数,如果值溢出超过0xFFFF或低于0x00,我需要结果等于限制(0x00或0xFFFF)。我想知道做这件事最快的方法是什么?我的方法如下所示,但它使用长数据类型,因此使用长二进制算法,所以我猜有一种更快的方法

long i;
unsigned int result;

i = someUINT + someCHAR;

if(i <= 0) 
{
    result = 0;
}
else if(i >= 0xFFFF)
{
    result = 0xFFFF;
}
else 
{
    result = (unsigned int)i;
}
longi;
无符号整数结果;
i=someUINT+someCHAR;
如果(i=0xFFFF)
{
结果=0xFFFF;
}
其他的
{
结果=(无符号整数)i;
}

编辑:我使用的是16位MCU(PIC24HJ系列)和微芯片C30编译器。

您可以避免在添加之前进行长时间的检查:

if(0xFFFF - someUINT < someCHAR) {
  return 0xFFFF;
} else {
  return someUINT + someCHAR;
}
if(0xFFFF-someUINT

当然,如果您真的需要快速执行,请将其转换为内联函数或宏并执行程序集。

此算法只适用于2的补码

检查带符号加法是否溢出时,结果必须与至少一个操作数具有相同的符号。事实证明,这种情况只是略有不同;如果结果翻转“符号”位,则如果两个操作数具有相同的“符号”位,则没有问题。当然,无符号极限的计算更容易

uint16_t UIntPlusChar(uint16_t u, char ch)
{
  int16_t i = (int16_t)u;
  int16_t p = i + ch;
  if ((ch ^ i) < 0 && (p ^ i) < 0)
    p = i >> 15;
  return (uint16_t)p;
}
uint16\u t UIntPlusChar(uint16\u t u,char ch)
{
int16_t i=(int16_t)u;
int16_t p=i+ch;
如果((ch^i)<0&(p^i)<0)
p=i>>15;
返回(uint16_t)p;
}

几乎可以肯定,正确的答案是

if(i <= 0) 
{
    result = 0;
}
else if(i >= 0xFFFF)
{
    result = 0xFFFF;
}
else 
{
    result = (unsigned int)i;
}
if(i=0xFFFF)
{
结果=0xFFFF;
}
其他的
{
结果=(无符号整数)i;
}
分析应用程序,如果这是一个瓶颈(我非常非常非常怀疑),那么重写它



现代编译器非常擅长为这样的代码编写无分支条件语句,所以只需以最有意义的方式编写它,并让编译器完成它的工作。不要把编译器和任何可怜的人都搞混了,他们将来要用一些复杂的小技巧来阅读这些代码。

哇,我喜欢这样的东西。这里是我的刺假设,大多数时候它会落在边界之间试试这个

    long i;
    i= char + int;
    if((i & 0xFFFF) == i){
      return (int)i;
    }
    else if(i < 0)
    {
      return 0;
    }
    else
    {
      return 0xFFFF;
    }
longi;
i=char+int;
if((i&0xFFFF)==i){
返回(int)i;
}
else if(i<0)
{
返回0;
}
其他的
{
返回0xFFFF;
}

最快的方法几乎总是利用可移植C代码中无法描述的处理器特定功能。编写工作正常的明显正确的可移植代码,让编译器做它将要做的事情。如果您有特定的基准测试数据表明这必须更快,那么实现一个额外的特定于处理器的优化版本

许多处理器(包括,我相信,PIC24)都有“饱和加法”指令,可以精确执行此操作。最快的事情通常是编写专门使用该指令的程序集,但除非有证据表明函数需要更快,否则没有理由这样做。

result=someUINT+someCHAR;
result = someUINT + someCHAR;
if (someCHAR > 0)
{
   if (result < someCHAR)
   {
      result = 0xFFFF;
   }
}
else if (result > someUINT)
{
   result = 0;
}
如果(someCHAR>0) { if(结果某些结果) { 结果=0; }
我想最快的应该是:

UInt16 uival; Int8 sbval; UInt16 result; result = uival + sbval; if (uival & 0x8000) /* Only worry about max-val overflow */ { if (result = 65280) /* Underflow */ result = 0; } UInt16 uival; Int8 sbval; UInt16结果; 结果=uival+sbval; if(uival&0x8000)/*只担心最大值溢出*/ { 如果(结果=65280)/*底流*/ 结果=0; }
事情有点简化,因为任何溢出都只能发生在数值范围的一小部分。如果加数为16位,则有必要测试原始uint16与结果之间的差异,以查看是否存在溢出;因为加数只有8位,所以不需要。我没有使用PIC24xx部件,所以我不知道256或65280的测试速度是否比其他值快,但在8位部件上肯定应该快。

这应该在什么硬件上运行?这个问题的答案完全取决于硬件平台。如果使用
long
(我假设它在这个所谓的处理器上是字大小的两倍?)太慢,那么您可能需要降到汇编级别,以便检查溢出标志。@Mike Caron:我不一定说使用long会太慢,我只是想知道是否有更快的方法。@Mike Caron:你能用一个基本的例子来回答这个问题吗。如果它不适合我的处理器,我不会感到不安。@Jordan:我很想发布一个答案,但我不做机器组装。(.NET汇编,当然…;)别忘了someCHAR可以是负数:
someUINT=10;someCHAR=-42。。。。六羟甲基三聚氰胺六甲醚。。。你需要特别注意“积分升级”和“常用算术转换”!!!为什么添加一个操作会使它更快?@BlueRaja,
如果((i&0xFFFF)==i)
是2个带分支的超快速(仅寄存器)指令,那么应该也会预测到。如果是这样,那就是保持边界,解决方案是好的!(提供的不仅是好的,而且是最好的);编辑,现在我看到CPU只有16位,不是这样hot@bestsss:…是,并且
i>=0xFFFF
是一条带分支的指令。不仅如此,它的意图更为明确。@BlueRaja,
(i&0xFFFF)==i
确保i的值在0-0xFFFF范围内,这就是诀窍;这是最常见的情况,如果预测正确(应该是),它不会花费任何费用。相反,您需要两个比较分支来确保相同的范围。这种推测对16位CPU可能是无效的,我不知道它是如何工作的,它也没有32位的寄存器