9

Is there a good general pattern for implementing truth tables?

I am re-working some legacy code (C++) and just realized that the function I am working with amounts to a truth table with 3 binary inputs and 8 possible outputs. Here is an example of two of the eight tests and corresponding outputs:

// - + +
if ( (prevdst5 < 0.0) && (dst5 > 0.0) && (nextdst5 > 0.0) ){
    thawpct = (dst5 / (dst5 - prevdst5));
}

// - - +
if ( (prevdst5 < 0.0) && (dst5 < 0.0) && (nextdst5 > 0.0) ){
    thawpct = (nextdst5 / (nextdst5 - dst5));
}

// other cases...

return thawpct;

Basically I am wondering if there is a cleaner, more maintainable/extensible* way to set this up.

  • What if another input is added? Then the number of if statements needed would be 16, which in my view, would be too cumbersome to manage with the current pattern.
  • What if several of the input combos should map to the same output?

*The codebase is an ecosystem model used in academia, so maintenance and extension amount to similar things depending on the perspective of the coder.

tbc
  • 1,679
  • 3
  • 21
  • 28
  • Are you sure? is dst5 = 0.0 somewhere else, or out of scope? – Tony Hopkinson Jun 18 '12 at 17:21
  • not sure I understand? there is actually a test at the top of the function: if (dst5 == 0.0) dst5 = 0.001; which I think is a bug (compare floating point number for equality) – tbc Jun 18 '12 at 17:25
  • (too late to modify previous comment) Fix here: not sure I understand? there is actually a test like this: if (dst5 == 0.0) dst5 = 0.001; for each input at the top of the function. I actually think this is a bug (compare floating point number for equality) but at least takes care of the possibility of each input being 0. – tbc Jun 18 '12 at 17:32
  • ,not inthe code you posted there isn't. Equality on floating points is always iffy as you can't garantee an exact representation. Rounding or <=, >= usually takes care of it. – Tony Hopkinson Jun 18 '12 at 21:12

3 Answers3

9
int condition = ( prev >= 0 ? ( 1<<0 ) : 0 ) + 
                ( cur >= 0  ? ( 1<<1 ) : 0 ) + 
                ( next >= 0 ? ( 1<<2 ) : 0 );

switch (condition) {
  case 0: // - - -
  case 1: // + - -
  case 2: // - + -
  case 3: // + + -
  case 4: // - - +
  case 5: // + - +
  case 6: // - + +
  case 7: // + + +
}
CAFxX
  • 28,060
  • 6
  • 41
  • 66
  • 2
    If two inputs map to the same output you just put those cases next to each other and fall-through. Even simpler than my array suggestion. – Jonathan Wakely Jun 18 '12 at 17:31
  • I have seen the conditional operator before, but I am confused by the "1<<0" in the second operand? Johathan Wakely used something similar in his answer... – tbc Jun 18 '12 at 17:42
  • @myself - found it shifting operator: http://stackoverflow.com/questions/141525/absolute-beginners-guide-to-bit-shifting – tbc Jun 18 '12 at 17:49
4

An array is a table.

A sequence of boolean truth values is a binary number.

Arrays are indexed by number.

Sooooo .....

You could define a function for each calculation:

// - + + == 0 1 1 == 3
inline double f3(double prev, double curr, double next)
{
  return curr / (curr - prev);
}

// - - + == 0 0 1 == 1
inline double f1(double prev, double curr, double next)
{
   return next / (next - curr);
}

// ...

Then declare an array of function pointers:

typedef double (*func_type)(double, double, double);
func_type funcs[8] = {
  f1, f2, // ...
};

Then index into the array using the boolean conditions as binary digits:

func_type f = funcs[ (int(prevdst5 < 0.0)<<2) | (int(dst5 < 0.0)<<1) | int(nextdst5 > 0.0) ];
thawpct = f(prevdst5, dst5, nextdst5);
  • What if another input is added? (Then the number of tests would be 16, which in my view would be cumbersome to manage with the current pattern)

You double the size of the array and add f8, f9 etc. if different calculations are needed, but you only add the new test once, in the array index:

func_type f = funcs[ (cond<<3) | (int(prevdst5 < 0.0)<<2) | (int(dst5 < 0.0)<<1) | int(nextdst5 > 0.0) ];
  • What if several of the input combos should map to the same output?

Store the same function pointer at several elements of the array:

func_type funcs[8] = {
  f1, f2, f3, f1, f1, // ...
};
Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
0

You could keep a mapping of 3 (or n) values to the appropriate function that needs to be performed. Then loop up the function in this map based on the true/false state of the conditons and execute that.

This way you would have an 3 dimentional map (with size 2 in all dimentions)

Attila
  • 28,265
  • 3
  • 46
  • 55