需要:Wrappable Counter<和>做“正确的事”

时间:2009-01-19 15:51:29

标签: c count overflow

我需要一个允许溢出的couter的代码,其中< >对于某些定义的时间间隔,继续告诉以后值的早期值。

澄清一下,一种可能的实施方式是:

考虑两个这样的计数器curdut(被测设备),考虑两个函数:

bool isEarlier(cur, dut)    // Is dut earlier than cur?
bool isLater(cur, dut)

curdut是16位,cur刚刚溢出,其当前值是,假设5。根据{{​​1}}的值,函数将返回

  • 0到16384:isEarlier - &gt; dut,isLater - &gt; (cur < dut)
  • 16384至32768:isEarlier - &gt; false,isLater - &gt;真
  • 32768至49152:无效,记录错误
  • 49152至65536:isEarlier - &gt;是的,isLater - &gt;假

我可以自己编写代码,没问题。我只是懒惰。我知道事实上在PostgreSQL中存在类似的东西(事务ids包装),我无法找到实际执行它的函数。我很确定在Linux内核中有类似的东西,可能是宏。但是更高级的谷歌代码搜索,以及/ usr / include / linux上的grep可能会把它变成现实。有什么想法吗?

澄清了cur和dut的作用。 “无效”是一种保障措施。随着cur和dut之间的差异变大,这个功能最终会引起注意。

5 个答案:

答案 0 :(得分:3)

我认为你正在谈论正确处理数字圆的环绕。实际上这很容易。

这并不是你所说的(不确定为什么你有“异常”间隔),但是:

typedef unsigned short uint16_t;
typedef signed short int16_t;
// abstract out 16-bit types in case "short" doesn't correspond to 16bits

bool isEarlier(uint16_t a, uint16_t b)
{
   int16_t diff = a-b;
   return diff < 0;
}
bool isLater(uint16_t a, uint16_t b)
{
   int16_t diff = a-b;
   return diff > 0;
}

编辑:这在diff = -32768处有一个“分支点”,因此如果a = 5且b = 32772,则diff = -32767小于0,因此5为“早于“32772.如果a = 5且b = 32774,diff = -32769 = 32767大于0,因此5”晚于“32774”。这定义为“早期”和“后期”(a) )最简单的数学运算,以及(b)因为环绕计数器可以被解释为具有多个解mod6536,所以它选择a和b的解相对于数字圆相互“最接近”。

如果a和b相差32768那么它们相距很远而且简单的数学用于选择最简单的...这“违反”了isLater(5)中“早期”和“后期”的反对称属性,32773)是真的,isLater(32773,5)也是如此。但是你怎么知道“5”代表5的数量,或者“5”代表65541的数量? (正如abs(-32768)== -32768给出一个奇怪的荒谬答案)如果你想保持反对称,例如isLater(b,a)== isEarlier(a,b),那么你总是可以这样做:

bool isLater(uint16_t a, uint16_t b)
{
   int16_t diff = b-a;
   return diff < 0;
}

如果您希望将分支点向一个方向偏置,发生在-32768 + K,请改用:

bool isEarlier(uint16_t a, uint16_t b)
{
   int16_t diff = a-b-K;
   return diff < -K;
}
bool isLater(uint16_t a, uint16_t b)
{
   int16_t diff = b-a-K;
   return diff < -K;
}

这不再使用最近的;例如,如果K = 12768,a = 5,那么对于b = 6,7,8,9,... 20005,isEarlier(a,b)和isLater(b,a)将为真,并且对于b = 20006,20007,... 65534,65535,0,1,2,3,4,5 isEarlier(a,b)和isLater(b,a)将为false。

您有特定的间隔选择,这与我使用环绕数字的理由不同。这里定义的功能不能满足你所​​说的需求,但我觉得这些间隔的选择有点奇怪。也许你可以解释一下你是如何决定的?

答案 1 :(得分:1)

首先计算差异,然后检查它落入哪个窗口。

由于它非常简单并且过去/未来/错误窗口的大小各不相同,因此您必须自己完成。

答案 2 :(得分:1)

好的,记录。这是我的解决方案,这就是我的意思:

#include <stdint.h>


void increase_cyclic_counter (uint16_t *cnt)
{
#ifdef CYCLIC_COUNTER_EXPLICIT_WRAP
    if (*cnt < 2^16-1)
        *cnt++;
    else
        *cnt = 0;
#else
    *cnt++;
#endif
}


#define SAME 1
#define LATER 0
#define EARLIER 2
#define FORBIDDEN -1

/* dut (device under test) is tested against cur
 * returns:
 *    EARLIER (LATER) if dut happened earlier (later) in the sequence than cur
 *    SAME            if dut == cur
 *    FORBIDDEN       if dut and cur are that far away in the cyclic sequence
 *                    that no unambigious jugement is possible
 *
 * The basic idea is the same as with two-character year codes, where 
 * '97' stands for 1997 and '11' stands for 2011. '50' is regarded as 
 * too ambigous and therefore rejected.
 *
 * The implementation splits the short integer range 0-65535 into 4 parts:
 *   0-16383, 16384-32767, 32768-49151, 49152-65536
 * With cur and dut in the same range, normal arithmetics apply, else the 
 * ranges are compared to each other.
 */

int test_cyclic_counter (uint16_t cur, uint16_t dut)
{
    switch (((int)(cur>>14)) - ((int)(dut>>14)))
    {
        case 0:  // same range
            if (dut < cur) 
                return EARLIER;
            else if (dut == cur)
                return SAME;
            else 
                return LATER;

        case 1:
        case -3:
            return EARLIER;

        case 3:
        case -1:        
            return LATER;

        default: 
            return FORBIDDEN;
    }
}

答案 3 :(得分:0)

在我看来你刚刚写了:)。 为什么不将你的帖子翻译成一些C代码?

答案 4 :(得分:0)

请记住,你不能得到“&gt;”和“&lt;”在C中做你想做的事。它们仅适用于数字,并且没有运算符重载。同样的事情也适用于你的例外; C没有例外。

你可以编写一些访问函数,以这种方式处理无符号整数类型,这并不困难。 (在C中,对于有符号整数类型,溢出是未定义的,尽管在大多数现代系统中它都包含在内。)这不会那么困难。