简体   繁体   English

很长的if..else声明

[英]Long if..else statement

How do I reduce long if..else statement such as this one? 如何减少if..else这样的long语句?

if( strcmp( alnumToc, "log") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_log( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "log2") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_log2( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "log10") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_log10( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "sqrt") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_sqrt( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "cbrt") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_cbrt( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "abs") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_abs( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "sin") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_sin( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "cos") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_cos( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "csc") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_csc( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "cot") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_cot( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "acos") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_acos( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "asin") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_asin( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "atan") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_atan( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "cosh") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_cosh( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        } else if( strcmp( alnumToc, "sinh") == 0){
            ARGNUMCHECK( in, 1);
            mpfr_sinh( num, stack[j-1], MPFR_RNDN);
            CPYRES( 1);
        }

It's not just ugly but also slow. 它不仅丑陋而且缓慢。 I thought of using hashtable with function pointers. 我想过使用带有函数指针的哈希表。 Is that good solution? 那是好的解决方案吗?
Note: there will be some mpfr functions, that take more arguments, so I can't create just one macro. 注意:会有一些mpfr函数,它们需要更多的参数,所以我不能只创建一个宏。

That is very poor code and indeed it will be very slow. 这是非常糟糕的代码,实际上它会非常慢。 It must be rewritten from scratch. 它必须从头开始重写。

The fastest possible way is to store all string literals in a sorted array, then use bsearch to search through it. 最快的方法是将所有字符串文字存储在已排序的数组中,然后使用bsearch搜索它。 Use an array of structs where the string is the search key. 使用字符串数组,其中字符串是搜索键。 You'll have to write your own comparison function for your struct type. 您必须为结构类型编写自己的比较函数。

If you find the string you were looking for, call its corresponding function through the function pointer: 如果找到要查找的字符串,请通过函数指针调用其对应的函数:

typedef struct
{
  const char*  STRING;
  func_t       action;
} my_str_thing;

const my_str_thing TABLE [N] =
{
  { "ABC", do_this},
  { "DEF", do_that},
  ...
};

A hash table would work out too, but seems needlessly complex for this specific case. 哈希表也可以解决,但对于这个特定的情况似乎是不必要的复杂。

  1. Store all of the names and functions in a structure: 将所有名称和函数存储在结构中:

     struct calcRoutine_t { const char *name; void (*function)(int, int, int); } calc_routine[] = { { "log", mpfr_log }, { "log2", mpfr_log2 }, { "log10", mpfr_log10 }, { "sqrt", mpfr_sqrt }, { "cbrt", mpfr_cbrt }, { "abs", mpfr_abs }, { "sin", mpfr_sin }, { "cos", mpfr_cos }, { "csc", mpfr_csc }, { "cot", mpfr_cot }, { "acos", mpfr_acos }, { "asin", mpfr_asin }, { "atan", mpfr_atan }, { "cosh", mpfr_cosh }, { "sinh", mpfr_sinh } }; 
  2. Loop over the array and use strcmp to locate the correct function: 遍历数组并使用strcmp定位正确的函数:

     for (i=0; i<sizeof(calc_routine)/sizeof(calc_routine[0]); i++) { if (!strcmp ( calc_routine[i], alnumToc) ) { ARGNUMCHECK( in, 1); calc_routine[i].function (num, stack[j-1], MPFR_RNDN); CPYRES( 1); break; } } 

    (You can add a flag for 'success' before the break , or test if i == sizeof(calc_routine) /sizeof(calc_routine[0]) at the bottom.) (你可以在break之前为'success'添加一个标志,或者在底部测试i == sizeof(calc_routine) /sizeof(calc_routine[0]) 。)

This has the initial advantage you can add, shuffle, and remove any of the sub-routines at will. 这具有初始优势,您可以随意添加,随机播放和删除任何子例程。

As soon as you decided on a final set of names/functions, sort them once by name and then use bsearch instead of this loop. 一旦你决定了最后一组名称/函数,按名称对它们进行一次排序,然后使用bsearch代替这个循环。 On success, bsearch will point to the correct structure member and you can call its associated function right away; 成功后, bsearch将指向正确的结构成员,您可以立即调用其相关的功能; on failure, bsearch will return NULL . 如果失败, bsearch将返回NULL

Add

As noted in a comment, some functions may need more arguments than 1. This number can be stored in the struct calcRoutine_t as well, to be tested in the loop. 如注释中所述,某些函数可能需要比1更多的参数。此数字也可以存储在struct calcRoutine_t中,以便在循环中进行测试。

The performance issue came from that strcmp repeatedly scan the same string over and over again. 性能问题来自于strcmp一遍又一遍地重复扫描相同的字符串。

If your input data is clean, means no unexpected content in alnumToc , you can actually skip lots of characters comparison to gain performance. 如果您的输入数据是干净的,意味着alnumToc没有意外内容,您实际上可以跳过大量字符比较以获得性能。 Try this: 尝试这个:

switch(alnumToc[0]) {
  case 'a': // abs, acos, asin or atan, you don't have to check beyond alnumToc[1]
    switch(alnumToc[1]) {
      case 'b'
        // deal with "abs"
        break;
      case 'c'
        // deal with "acos"
        break;
      case 's'
        // deal with "asin"
        break;
      case 't'
        // deal with "atan"
        break;
    }
    break;

  case 'l': // log, log2, or log10, "og" is common, no need to check
    switch(alnumToc[3]) {
      case '\0' // terminator of c string
        // deal with "log"
        break;
      case '2'
        // deal with "log2"
        break;
      case '1'
        // deal with "log10"
        break;
    }
    break;
  // you can figure out the rest
}

The bottom line is to only scan alnumToc once for best performance. 最重要的是只扫描alnumToc一次以获得最佳性能。 If you cannot guarantee alnumToc is clean, exhause all alnumToc[0], [1], [2], ... . 如果你不能保证alnumToc是干净的,请尽量使用所有alnumToc[0], [1], [2], ...

1. Instead keep all strings in an array. 1.而是将所有字符串保留在数组中。

char *strarray[] = {"log", "log2", "blah Blah"};

2. Run a for loop like 2.运行for循环

for(i = 0; i < NO_OF_STRINGS; i++)
{
    // strcmp
}   

3. Keep array of function pointers for mpfr_sqrt, mpfr_acos,.. 3.保留mpfr_sqrt,mpfr_acos,... 的函数指针数组

It will reduce code size. 它会减少代码大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM