【问题标题】:Optimize multiple comparison conditions优化多重比较条件
【发布时间】:2020-02-13 14:03:35
【问题描述】:

我的主要代码需要比较一个整数 ASCII 命令,我想知道是否有解决方案来优化这个。

我可以在串行总线上从 '1' 发送到 '128' 并到达正确的对象,我是这样做的:

// this is how I deal with the data sent on the serial bus 
int translateASCII(char requestBuffer[10]){
    char word[4] = {0};
    word[0] = (int)requestBuffer[0];
    word[1] = (int)requestBuffer[1];
    word[2] = (int)requestBuffer[2];
    int n = atoi(word);
    return n;
}

void interpreteASCII(int ascii){
    if (ascii > 0 && ascii < 33){
        if (ascii < 9){
            blabla
        }
        else if (ascii < 17){
            blabla
        }
        else if (ascii < 25){
            blabla
        }
        else
            blabla
    }
    else if (ascii < 65){
        if (ascii < 41){
            blabla
        }
        else if { ... }
    }            
}

所以我正在寻找一种优化这种“架构”的方法。还考虑了一个 switch case 函数,但它似乎只将我的 ASCII 变量与单个整数进行比较,例如:

switch (ascii){
     case '8':
         blabla

这不是我要找的,因为指令实际上取决于按 32 间隔排序的 ASCII 变量,而这些变量本身必须按 8 个值的间隔排序。

【问题讨论】:

  • 不要使用magic numbers,也许the standard character classification functions 可以帮助你?
  • 或者,如果您应该明确处理 ASCII,但不确定您的程序语言环境字符集是否与 ASCII 兼容,那么请创建您自己的字符分类函数。它将使您的代码更具可读性。
  • 事实是我对 C 不是超级友好,像初学者或其他什么,所以我真的不知道如何正确地做到这一点
  • 那些神奇的数字 17、25、33、41 和 65 是什么?
  • 我用这些来制作 8 的范围

标签: c# optimization range comparison


【解决方案1】:

您说每个 8 间隔需要一个案例,例如1-8、9-16 等。试试这个:

switch ((ascii + 7)/ 8) {
case 0: // input was zero
    break;
case 1: // input was in [1..8]
    break;
// ...
case 8: // input was in [57..64]
    break;
}

【讨论】:

    【解决方案2】:

    首先,把int去掉,换成char或者uint8_t。您似乎不太可能拥有带有负索引的符号表。

    接下来,您基本上是在检查某些内容是否在特定的时间间隔内。使用 if-else 最不有效的方法是按升序进行:

    if(ascii < 17)
      ...
    else if(ascii < 25)
      ...
    else if(ascii < 33)
      ...
    

    显然“幻数”应该替换为常量或字符文字。

    如果间隔为 8(这不是您的幻数给出的),您可以通过执行 ascii / 8 作为查找来提高性能。通过普通开关或通过函数指针查找。后者的例子:

    #include <stdio.h>
    #include <stdint.h>
    
    void f0_7   (uint8_t n) { printf("%d %s\n", n, __func__); }
    void f8_15  (uint8_t n) { printf("%d %s\n", n, __func__); }
    void f16_23 (uint8_t n) { printf("%d %s\n", n, __func__); }
    ... // up to 127
    
    void interpreteASCII(uint8_t ascii)
    {
      typedef void(lookup_func)(uint8_t);
      lookup_func* const LOOKUP[] = { f0_7, f8_15, f16_23, ... /* up to 127 */ };
    
      LOOKUP[ascii/8](ascii);
    }
    
    int main (void)
    {
      for(uint8_t i=0; i<24; i++)
      {
        interpreteASCII(i);
      }
    
      return 0;
    }
    

    (不过,在调用此类表查找之前进行一些边界检查并不是一个坏主意。)

    【讨论】:

      【解决方案3】:

      不清楚您所说的“优化”是什么意思。

      • 您希望它具有尽可能小的内存占用吗?那么 John Zwinck 的答案(或类似的答案)可能是你最好的选择。

      • 您希望它尽可能快地运行吗?那么由 128 个条目组成的查找表(其中许多包含相同的值)将是最好的方法。

      • 您希望它尽可能易于阅读和理解吗?那么没有什么比你已经想出的解决方案更好了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多