Hi jlf
My previous code was wrong! It loop forever :). I didn't check it at all. Here is the tested code with optimization as well (the idea is the same).
The optimization is based on the fact that every time we change the state of the current position we dont have to do the multiplication again we can calculate the new result from the previous result as follow:
newResult = oldResult * valueOfNewStateAtCurentPos / valueOfOldStateAtCurentPos. The only time we have to do the multiplication is when valueOfOldStateAtCurentPos == 0 which makes oldResult == 0, and 0 multiply by whatever is always 0 that's why we have to re-calculate it.
Here is the new code
// Combi.cpp : Defines the entry point for the console application.
//
Code:#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define MAX_STATE 1 // 0 to 2
#define MAX_POS 3
// Make all these variable global to save the stack space, since we will do recursive
enum NLoopDirection {nldForward, nldBackward};
NLoopDirection LoopDirection;
int CurPos, States[MAX_POS];
double A[MAX_POS][MAX_STATE+1];
double MinValue, MaxValue, Result;
// helper to check the result and output interested value
void CheckResult()
{
int pos;
if (MinValue <= Result && Result <= MaxValue)
{
for (pos = 0 ; pos < MAX_POS ; ++pos)
printf("A%d[%d] = %f, ", pos, States[pos], A[pos][States[pos]]);
printf("Result = %f\n", Result);
}
}
// helper for calculating the saving result
void CalculateResult(int oldState)
{
// the calculation is as follows: Result = Result * newValueAtCurPos / oldValueAtCurPos
if (Result)
Result *= A[CurPos][States[CurPos]] / A[CurPos][oldState];
else if (0 == A[CurPos][oldState])
{
// result == 0 because the oldValueAtCurPos == 0, ===>>> we have to re-calculate the result
int i;
Result = 1;
for (i = 0 ; i < MAX_POS ; ++i)
if (0 == (Result *= A[i][States[i]]))
break;
}
}
// real part here
void DoMul()
{
bool stop = false;
int pos, oldState;
// check to increase the state of the current pos
oldState = States[CurPos];
if (LoopDirection == nldForward)
{
if (States[CurPos] < MAX_STATE)
++States[CurPos];
else
{
// need to find out the next position to increase
for (pos = CurPos ; pos < MAX_POS ; ++pos)
{
if (States[pos] < MAX_STATE)
{
// it's ok to increase the state of this pos and update the value of result
CurPos = pos;
oldState = States[CurPos];
++States[CurPos];
break;
}
}
if (MAX_POS == pos)
{
LoopDirection = nldBackward;
CurPos = MAX_POS-2;
oldState = States[CurPos];
++States[CurPos];
}
}
}
else
{
if (States[CurPos] > 0)
--States[CurPos];
else
{
// need to find out the next position to decrease
for (pos = CurPos ; pos >= 0 ; --pos)
{
if (States[pos] > 0)
{
// it's ok to decrease the state of this pos and update the value of result
CurPos = pos;
oldState = States[CurPos];
--States[CurPos];
break;
}
}
if (pos < 0)
return; // done
}
}
CalculateResult(oldState);
CheckResult();
DoMul();
}
void DoTest()
{
int pos, state;
// init MinValue, MaxValue
MinValue = 0;
MaxValue = 1.0;
// Init the states array
memset(States, 0, MAX_POS*sizeof(int));
// Init the double arrays
for (pos = 0 ; pos < MAX_POS ; ++pos)
for (state = 0 ; state <= MAX_STATE ; ++state)
A[pos][state] = (double)rand()/RAND_MAX;
// Calculate the Result for the first permutation.
// result is used as the saving value in each permutation to speed up the performance.
Result = 1;
for (pos = 0 ; pos < MAX_POS ; ++pos)
if (0 == (Result *= A[pos][0]))
break;
// check the first result
CheckResult();
// and call DoMul
CurPos = 0;
LoopDirection = nldForward;
DoMul();
};
int main(int argc, char* argv[])
{
DoTest();
return 0;
}
