This is a typical linear programming problem and there are several algorithms to solve it. You could use, for example, a Simplex maximization algorithm.
Many people prefer to use Excel to solve this type of problem because it already comes with tools such as Hypothesis Test and Solver, implementing some linear programming algorithms.
In particular, I find the implementation of these algorithms complex. After my Operational Research classes (and that was a long time ago!), I never needed to implement one of them. Of the few times I came across a problem like this, I used Excel even.
Solution 1
For a robust and efficient solution, I suggest you implement in your system a linear programming algorithm. You find an implementation of the Simplex maximization method in Simplex maximization Algorithm in C#.
Solution 2
For a much simpler solution, you can set up a loop of hypothesis tests until you find the most suitable value.
Whereas you want to find the value of dbi
resulting in the highest possible value for valorFaturamentoPrevistoObra
, the algorithm below loops to test assumptions of the billing value until you find the maximized value (the detailed explanation is in the comments).
Taxa taxa = new Taxa();
var listaTaxas = taxa.ListaTaxaOrcamento(orcamento_id);
//Crie uma varíavel para determinar o menor valor possível do faturamento
decimal faturamentoMinimo = (subtotalGrupo1 + subtotalGrupo2 + valorDespesasEspecificas);
//Crie uma variável para testar hipóteses de valor do faturamento
//Como se quer um valor maximizado, inicie o valor da hipoótese com um valor bem alto
//Estou sugerindo aqui que seja 3 vezes o faturamento mínimo mas pode ser maior ou menor
//Lembrando que, quanto maior, mais lenta será a execução
decimal hipoteseFaturamento = 3 * faturamentoMinimo;
//Faça um loop para testar o valor da hipótese até o limite mínmo
while (hipoteseFaturamento > faturamentoMinimo)
{
//calcule a taxa de rateio com base no valor da hipótese
taxaRateioAdmCentral = (valorAdmCentralPeriodo * (hipoteseFaturamento / (valorFaturamentoPeriodo + hipoteseFaturamento)) / (subtotalGrupo1 + subtotalGrupo2)) * 100;
//Calcule o bdi
bdi = CalculaBDI(orcamento_id, listaTaxas, valorDespesasEspecificas, taxaRateioAdmCentral);
//Calcule o faturamento previsto
valorFaturamentoPrevistoObra = ((subtotalGrupo1 + subtotalGrupo2) + valorDespesasEspecificas) * (1 + bdi);
//Verifique se o faturamento previsto é igual à hipótese,
//se for igual, você encontrou o bdi desejado
//se não for, diminua o valor da hipótese e calcule novamente
if (hipoteseFaturamento == valorFaturamentoPrevistoObra)
break;
else
hipoteseFaturamento -= 1;
}
I believe you will have to carry out an iterative process. Assign an initial value to bdi and perform the calculation several times, using the value obtained in each step for bdi as input for the next iteration, until you reach the desired error or a number of predefined iterations.
– Magnetron
PS: the iterative method is how Excel resolves circular references: https://excelmaniacos.com/2016/12/dicas-quando-a-referencia-circular-e-desired/
– Magnetron
I believe that is not the case of circular reference. Like excel, passing to C#, a circular reference would be something like:
x = x +1;
that is: The variable is used in its own calculation, not that of "a variable being used before having a defined value". I believe that the problem there is of logic, maybe if we explain the calculation better or even show the spreadsheet with her formula, we can help– Rovann Linhalis
maybe help: http://constructcaomercado17.pini.com.br/negocios-incorporacao-construcao/95/especial-obras-publicas-calcular-o-bdi-281833-1.aspx
– Rovann Linhalis