using System.Collections.Generic;
public static void Main()
var servico = new ServicoDeRateio();
var items = servico.Ratear(10M, 6, PoliticaArredondamentoRateio.DoisDecimais);
public enum PoliticaArredondamentoRateio
public class ServicoDeRateio
public IEnumerable<decimal> ArredondarTotalRateado(IEnumerable<decimal> valoresRateados, decimal valorTotalParaRatear, PoliticaArredondamentoRateio politicaDeArredondamento)
decimal fator = Fator(politicaDeArredondamento);
var valores = valoresRateados.ToList();
var indicesOrdenadosPelosDecimaisRestantes = new List<KeyValuePair<int, decimal>>();
for (var i = 0; i < valores.Count; i++)
indicesOrdenadosPelosDecimaisRestantes.Add(new KeyValuePair<int, decimal>(i, valores[i] * fator - Math.Floor(valores[i] * fator)));
valores[i] = this.ArredondarValor(valores[i], politicaDeArredondamento);
indicesOrdenadosPelosDecimaisRestantes = indicesOrdenadosPelosDecimaisRestantes.OrderByDescending(p => p.Value).ToList();
decimal totalJaRateado = valores.Sum();
decimal diferenca = valorTotalParaRatear - totalJaRateado;
valores[indicesOrdenadosPelosDecimaisRestantes.OrderByDescending(w => w.Value).FirstOrDefault().Key] += valor;
valores[indicesOrdenadosPelosDecimaisRestantes.OrderBy(w => w.Value).FirstOrDefault().Key] += valor;
public decimal ArredondarValor(decimal valor, PoliticaArredondamentoRateio politicaDeArredondamento)
decimal fator = Fator(politicaDeArredondamento);
return decimal.Truncate(valor * fator) / fator;
public decimal Fator(PoliticaArredondamentoRateio politicaDeArredondamento)
switch (politicaDeArredondamento)
case PoliticaArredondamentoRateio.DoisDecimais:
case PoliticaArredondamentoRateio.QuatroDecimais:
return (int)Math.Floor(Math.Pow(10, i));
#region Funções de rateio
public IEnumerable<decimal> Ratear<T>(decimal valorTotalParaRatear, IEnumerable<T> listaDeItens, Func<T, decimal> valorDeUmItem, PoliticaArredondamentoRateio politicaDeArredondamento)
decimal total = listaDeItens.Sum(valorDeUmItem);
IList<decimal> listaDeRateios = new List<decimal>();
foreach (var item in listaDeItens)
var valor = valorDeUmItem.Invoke(item);
decimal valorRateado = (total * valor) == 0 ? 0 : valorTotalParaRatear / total * valor;
listaDeRateios.Add(valorRateado);
listaDeRateios = this.ArredondarTotalRateado(listaDeRateios, valorTotalParaRatear, politicaDeArredondamento).ToList();
return listaDeRateios.AsEnumerable();
public IEnumerable<decimal> Ratear<T>(decimal valorTotalParaRatear, IEnumerable<T> listaDeItens, Func<T, decimal> valorDeUmItem, PoliticaArredondamentoRateio politicaDeArredondamento, Action<T, decimal> atualizarListaAplicandoRateio)
var rateio = Ratear(valorTotalParaRatear, listaDeItens, valorDeUmItem, politicaDeArredondamento);
for (var i = 0; i < rateio.Count(); i++)
var valorRateado = rateio.ElementAt(i);
var item = listaDeItens.ElementAt(i);
atualizarListaAplicandoRateio(item, valorRateado);
public IEnumerable<decimal> Ratear(decimal valorTotalParaRatear, int quantidadeDeParcelas, PoliticaArredondamentoRateio politicaDeArredondamento)
IList<decimal> retorno = new List<decimal>();
if (valorTotalParaRatear % quantidadeDeParcelas != 0)
var valorParcela = valorTotalParaRatear / quantidadeDeParcelas;
for (int i = 0; i < quantidadeDeParcelas; i++)
retorno.Add(valorParcela);
retorno = this.ArredondarTotalRateado(retorno, valorTotalParaRatear, politicaDeArredondamento).ToList();
var valorParcela = valorTotalParaRatear / quantidadeDeParcelas;
for (int i = 0; i < quantidadeDeParcelas; i++)
retorno.Add(valorParcela);
return retorno.AsEnumerable();