Проблема со средней длиной в коде Фано

Средняя длина кода Фано рассчитывается как показано на скриншоте.

В коде я использовал метод Sum для подсчёта суммы. Выяснилось, что данный метод считает сумму для всех символов т.е (0.125 * 3 * 4 + 0.0625 * 4 * 8 = 3.5)

Правильный расчёт такой: 0.125 * 3 + 0.0625 * 4 = 0.625.

Как можно это скорректировать верно?расчет средней длины

class Program
{

    static void Main()
    {
        var symbols = new List<Symbol>
        {
            new Symbol("н", 0.125),
            new Symbol("к", 0.125),
            new Symbol("и", 0.125),
            new Symbol("о", 0.125),
            new Symbol("д", 0.0625),
            new Symbol("е", 0.0625),
            new Symbol("ь", 0.0625),
            new Symbol("с", 0.0625),
            new Symbol("м", 0.0625),
            new Symbol("а", 0.0625),
            new Symbol("в", 0.0625),
            new Symbol("т", 0.0625),
        };

        var sortedList = symbols.OrderByDescending(s => s.Probability).ToList();

        var resultList = CalculateSymbolsCodes(sortedList);

        Console.WriteLine("Name\tProbability\tCode");
        foreach (var item in resultList)
            Console.WriteLine($"\n{item.Name}\t{item.Probability}\t\t{item.Code}");

        double entropy = resultList.Sum(s =>
            s.Probability * Math.Log(s.Probability, 2)) * -1;

        double codeLength = resultList.Sum(s => (s.Probability * s.CodeLength));
        double efficiency = entropy / codeLength;
        Console.WriteLine($"\nCodeLength: {codeLength}");
        Console.WriteLine($"\nEfficiency: {entropy} / {codeLength} = {efficiency}");
    }

    static List<Symbol> CalculateSymbolsCodes(List<Symbol> symbols)
    {
        var cPoint = GetSeparationIndex(symbols) + 1;

        var topList = symbols.GetRange(0, cPoint);
        var bottomList = symbols.GetRange(cPoint, symbols.Count - cPoint);

        topList.ForEach(s => s.Code += "0");
        if (topList.Count > 1) CalculateSymbolsCodes(topList);

        bottomList.ForEach(s => s.Code += "1");
        if (bottomList.Count > 1) CalculateSymbolsCodes(bottomList);

        topList.AddRange(bottomList);

        return topList;
    }

    static int GetSeparationIndex(List<Symbol> symbols)
    {
        var dict = new SortedList<double, int>();
        var half = symbols.Sum(s => s.Probability) / 2;
        var sum = 0.0;
        for (var i = 0; i < symbols.Count; i++)
        {
            sum += symbols[i].Probability;
            var diff = Math.Abs(half - sum);
            if (!dict.ContainsKey(diff)) dict.Add(diff, i);
        }

        return dict.First().Value;
    }
}

class Symbol
{

    public Symbol(string name, double probability)
    {
        Name = name;
        Probability = probability;
        Code = "";
    }

    public string Name { get; set; }
    public double Probability { get; set; }
    public string Code { get; set; }
    public int CodeLength { get => Code.Length; }
  }
}

Ответы (0 шт):