You can create a set containing all possible sets of operations (for example, {-, -, -, -}, {-, -, -, +}, {-, -, +, -}, etc.) using the following function, which will list bool arrays, where true and false represent + and -. The vars parameter indicates the number of variables to combine. Please note that for 5 variables there are only 16 combinations (not 32, as you state), since there are 4 operators when combining 5 variables (if the first variable cannot be undone):
public List<bool[]> GetOperators(int vars) { var result = new List<bool[]>(); for (var i = 0; i < 1 << vars-1; i++) { var item = new bool[vars - 1]; for (var j = 0; j < vars-1; j++) { item[j] = ((i >> j) & 1) != 0; } result.Add(item); } return result; }
Once you have this list, you can use it to combine variables in all possible ways. First, we define a helper function that takes a set of variables and one combination of bool[] and applies it (it assumes that the number of combinations for the number of variables passed has the correct number of elements):
private double Combine(double[] vars, bool[] combination) { var sum = vars[0]; for (var i = 1; i< vars.Length; i++) { sum = combination[i - 1] ? sum + vars[i] : sum - vars[i]; } return sum; }
You can also format the combination beautifully using:
private string FormatCombination(double[] vars, bool[] combination) { var result = vars[0].ToString("0.00##"); for (var i = 1; i < vars.Length; i++) { result = string.Format("{0} {1} {2:0.00##}", result, combination[i - 1] ? "+" : "-", vars[i]); } return result; }
Putting it all together to check all possible combinations:
var vars = new [] { 1.23, // A 0.02, // B1 0.11, // B2 0.05, // C1 1.26 // C2 }; foreach (var combination in GetOperators(vars.Length)) { var combined = Combine(vars, combination); // Perform your operations on "combined" here... Console.WriteLine("{0} = {1}", FormatCombination(vars, combination), combined); }
This will output:
1.23 - 0.02 - 0.11 - 0.05 - 1.26 = -0.21
1.23 + 0.02 - 0.11 - 0.05 - 1.26 = -0.17
1.23 - 0.02 + 0.11 - 0.05 - 1.26 = 0.01
1.23 + 0.02 + 0.11 - 0.05 - 1.26 = 0.05
1.23 - 0.02 - 0.11 + 0.05 - 1.26 = -0.11
1.23 + 0.02 - 0.11 + 0.05 - 1.26 = -0.07
1.23 - 0.02 + 0.11 + 0.05 - 1.26 = 0.11
1.23 + 0.02 + 0.11 + 0.05 - 1.26 = 0.15
1.23 - 0.02 - 0.11 - 0.05 + 1.26 = 2.31
1.23 + 0.02 - 0.11 - 0.05 + 1.26 = 2.35
1.23 - 0.02 + 0.11 - 0.05 + 1.26 = 2.53
1.23 + 0.02 + 0.11 - 0.05 + 1.26 = 2.57
1.23 - 0.02 - 0.11 + 0.05 + 1.26 = 2.41
1.23 + 0.02 - 0.11 + 0.05 + 1.26 = 2.45
1.23 - 0.02 + 0.11 + 0.05 + 1.26 = 2.63
1.23 + 0.02 + 0.11 + 0.05 + 1.26 = 2.67
Edit:
For changes to your question, I updated my answer. As already mentioned, it is not necessary to use a full search such as this, but you can still find a useful method.
GetOperators() changes slightly to return 2 n- combinations (and not 2 n-1 as before):
public List<bool[]> GetOperators(int vars) { var result = new List<bool[]>(); for (var i = 0; i < 1 << vars; i++) { var item = new bool[vars]; for (var j = 0; j < vars; j++) { item[j] = ((i >> j) & 1) != 0; } result.Add(item); } return result; }
The Combine() method is modified to accept a set of increments in addition to the variables and combinations to be used. For each element of the combination, if it is true , the increment is added to the variable; if it is false, it is subtracted:
private double[] Combine(double[] vars, double[] increments, bool[] combination) { // Assuming here that vars, increments and combination all have the same number of elements var result = new double[vars.Length]; for (var i = 0; i < vars.Length; i++) { result[i] = combination[i] ? vars[i] + increments[i] : vars[i] - increments[i]; } // Returns an array of the vars and increments combined per the given combination // Eg if there are 5 vars and the combination is: {true, false, true, true, false} // The result will be {var1 + inc1, var2 - inc2, var3 + inc3, var4 + inc4, var 5 - inc5} return result; }
And FormatCombination() also updated to display the new combination style:
private string FormatCombination(double[] vars, double[] increments, bool[] combination) { var result = new List<string>(vars.Length); var combined = Combine(vars, increments, combination); for (var i = 0; i < vars.Length; i++) { result.Add(string.Format("{0:0.00##} {1} {2:0.00##} = {3:0.00##}", vars[i], combination[i] ? "+" : "-", increments[i], combined[i])); } return string.Join(", ", result.ToArray()); }
Putting it all together:
var vars = new[] { 1.23, // A 0.02, // B 0.11, // C 0.05, // D 1.26, // E }; var increments = new[] { 0.04, // incA 0.11, // incB 0.01, // incC 0.37, // incD 0.85, // incD }; foreach (var combination in GetOperators(vars.Length)) { var combined = Combine(vars, increments, combination); // Perform operation on combined here... Console.WriteLine(FormatCombination(vars, increments, combination)); }
Output (abbreviated):
1.23 - 0.04 = 1.19, 0.02 - 0.11 = -0.09, 0.11 - 0.01 = 0.10, 0.05 - 0.37 = -0.32, 1.26 - 0.85 = 0.41
1.23 + 0.04 = 1.27, 0.02 - 0.11 = -0.09, 0.11 - 0.01 = 0.10, 0.05 - 0.37 = -0.32, 1.26 - 0.85 = 0.41
1.23 - 0.04 = 1.19, 0.02 + 0.11 = 0.13, 0.11 - 0.01 = 0.10, 0.05 - 0.37 = -0.32, 1.26 - 0.85 = 0.41
1.23 + 0.04 = 1.27, 0.02 + 0.11 = 0.13, 0.11 - 0.01 = 0.10, 0.05 - 0.37 = -0.32, 1.26 - 0.85 = 0.41
...