【问题标题】:What is the best method to find the difference between two unsigned 16-bit numbers?找出两个无符号 16 位数字之间差异的最佳方法是什么?
【发布时间】:2021-10-22 17:19:14
【问题描述】:

简介:

假设您有两个 16 位无符号数,其值可以从 065535

假设我们有一个数组arr[2],它位于一个while循环中:

i = 0;
while(1){
  arr[i++] = Get_New_Value();
  if(i == 2)
     i = 0;
}

这很容易说可以测量,只需更改 while 循环,或读取它。

但假设您无法使用此 while 循环。您只有arr[2] 的读取权限,您的目标是找出arr[0]arr[1] 之间的区别。

我可以通过查看arr[0] < arr[1] 来衡量差异,然后您可以通过arr[1] - arr[0] 找到差异。或者如果arr[0] > arr[1],那么你就做arr[0] - arr[1]

但是现在听。函数Get_New_Value(); 是一个计数器,它从0 计数到65535 然后重新开始,这意味着如果arr[0] = 60000arr[1] = 2000,这意味着差异是65535 - arr[0] + arr[1] + 1,因为65536 实际上是0 用于无符号 16 位,655371。一切重新开始。

问题:

我不知道哪个索引具有最新更新的值,因为 arr 将其值插入,因为它是一个循环缓冲区。

问题:

如果我不知道哪个索引具有最新的更新值,我有什么办法可以找到具有两个索引值的arr 之间的区别?

其他信息:

计数器Get_New_Value();0 变为65535 需要6.5535

我将如何解决这个问题:

我会从arr[0]arr[1] 中取一个值并相互比较。我知道自从我得到这些值 arr[0]arr[1] 以来已经不到 6.5535 秒。

所以我只是比较一下

65535 - arr[0] + arr[1] + 165535 - arr[1] + arr[0] + 1 取决于哪个比另一个大。

【问题讨论】:

  • 连续调用Get_New_Value之间是否存在最大差异?
  • 为什么不知道哪个索引具有最新的更新值很重要?
  • @MrYui 在连续调用之间Get_New_Value的返回值可以改变多少?
  • @MrYui 那么问题是每次调用Get_New_Value之间可以经过多少秒?
  • 这是传感器数据采集中的常见问题。如果计数器以 ~1Hz 的频率递增,您可以轻松做到这一点

标签: c++ arrays c


【解决方案1】:

如果我们假设 Get_new_value 的调用频率高于每 3 秒一次,这意味着该值(考虑回绕后)的变化不会超过 uint16_t 范围的一半。

基于此,我们可以推断出最近的值是从它减去另一个的结果并且考虑回绕小于0x8000(或小于或-相等,取决于您要如何处理边界条件)。

可以按如下方式执行此检查:

if (arr[0] == arr[1]) {
    printf("no change\n");
} else if ((uint16_t)(arr[0] - arr[1]) < 0x8000)
    printf("arr[0] is more recent\n");
} else {
    printf("arr[1] is more recent\n");

以下是一些测试输入:

uint16_t values[][2] = {
  { 1, 2 },
  { 0x8003, 2 },
  { 0x8003, 0x1000 },
  { 0x9003, 0x1000 },
  { 0x1000, 0x8003 },
  { 0x1000, 0x9003 },
  { 0x1, 0xffff },
  { 0x1, 0x8000 },
  { 0x1, 0x8001 },
  { 0x1, 0x8002 },
};

然后输出:

arry[0]=0001, arr[1]=0002: arr[1] is more recent
arry[0]=8003, arr[1]=0002: arr[1] is more recent
arry[0]=8003, arr[1]=1000: arr[0] is more recent
arry[0]=9003, arr[1]=1000: arr[1] is more recent
arry[0]=1000, arr[1]=8003: arr[1] is more recent
arry[0]=1000, arr[1]=9003: arr[0] is more recent
arry[0]=0001, arr[1]=ffff: arr[0] is more recent
arry[0]=0001, arr[1]=8000: arr[1] is more recent
arry[0]=0001, arr[1]=8001: arr[1] is more recent
arry[0]=0001, arr[1]=8002: arr[0] is more recent

相关:Is detecting unsigned wraparound via cast to signed undefined behavior?

【讨论】:

  • 您能否展示一些模拟值,以便我们使用不同的值,并且可以确认该方法完美运行? =) 我喜欢你的回答。
  • 这里。我在这里发现了一个问题onlinegdb.com/MibiEDKR1
  • @MrYui 您的支票运作方式存在一些问题。我的替代作品。
  • 如果你看到这里func(50000, 65535)。区别很明显是65535 - 50000,但如果50000 是最新的计数器值,65535 是过去的计数器值,它也可以是50001
  • @MrYui 这就是假设对Get_new_value 的调用相隔永远不会超过 3 秒,或者更准确地说相隔 32768 个时钟滴答。否则无法判断哪个是最近的。
【解决方案2】:

你说Get_new_value 肯定会在 6 秒之间被调用。那么没有什么比这更容易了:

(arr[1] < arr[0]) ? 65536 - arr[0] + arr[1] : arr[1] - arr[0];

i = 0;
while(1){
  arr[i++] = Get_New_Value();
  if(i == 2)
     i = 0;
}

太长了。我会这样做

for (int i = 0; ; i %= 2)
  arr[i++] = Get_New_Value();

我假设数组是uint16_t arr[2];。我会像这样修改它

uint16_t arr[2][2]:
for (unsigned uint16_t i = 0; ; i++)
  arr[i / 2][i % 2]  = Get_New_Value();

毕竟 cmets 我会让 a[1] 始终是最近的值:

while (true) {
  a[0] = a[1];
  a[1] = Get_New_Value();
}

【讨论】:

  • 但是如果 arr[1]
  • 最新的值是多少并不重要。距离不变。如果您关心它,请更改循环:arr[0] = arr[1]; arr[1] = Get_New_Value();.
  • 什么不正确?模块65536“溢出”后距离正确。为什么要交换表达式中参数的顺序?
猜你喜欢
  • 2019-11-27
  • 2019-01-15
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 2021-02-17
  • 1970-01-01
  • 2021-02-18
相关资源
最近更新 更多