Long if..else statement
c, if-statement
Solution
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 }
};
Loop over the array and use `strcmp` to locate the correct function:
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.)
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. On success, `bsearch` will point to the correct structure member and you can call its associated function right away; on failure, `bsearch` will return `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.
Problem
How do I reduce long if..else statement such as this one? ``` 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.