Task: Arithmetic coding_As a generalized change of radix



C#: using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;

namespace AruthmeticCoding {
    using Freq = Dictionary<char, long>;
    using Triple = Tuple<BigInteger, int, Dictionary<char, long>>;

    class Program {
        static Freq CumulativeFreq(Freq freq) {
            long total = 0;
            Freq cf = new Freq();
            for (int i = 0; i < 256; i++) {
                char c = (char)i;
                if (freq.ContainsKey(c)) {
                    long v = freq[c];
                    cf[c] = total;
                    total += v;
                }
            }
            return cf;
        }

        static Triple ArithmeticCoding(string str, long radix) {
            
            Freq freq = new Freq();
            foreach (char c in str) {
                if (freq.ContainsKey(c)) {
                    freq[c] += 1;
                } else {
                    freq[c] = 1;
                }
            }

            
            Freq cf = CumulativeFreq(freq);

            
            BigInteger @base = str.Length;

            
            BigInteger lower = 0;

            
            BigInteger pf = 1;

            
            
            foreach (char c in str) {
                BigInteger x = cf[c];
                lower = lower * @base + x * pf;
                pf = pf * freq[c];
            }

            
            BigInteger upper = lower + pf;

            int powr = 0;
            BigInteger bigRadix = radix;

            while (true) {
                pf = pf / bigRadix;
                if (pf == 0) break;
                powr++;
            }

            BigInteger diff = (upper - 1) / (BigInteger.Pow(bigRadix, powr));
            return new Triple(diff, powr, freq);
        }

        static string ArithmeticDecoding(BigInteger num, long radix, int pwr, Freq freq) {
            BigInteger powr = radix;
            BigInteger enc = num * BigInteger.Pow(powr, pwr);
            long @base = freq.Values.Sum();

            
            Freq cf = CumulativeFreq(freq);

            
            Dictionary<long, char> dict = new Dictionary<long, char>();
            foreach (char key in cf.Keys) {
                long value = cf[key];
                dict[value] = key;
            }

            
            long lchar = -1;
            for (long i = 0; i < @base; i++) {
                if (dict.ContainsKey(i)) {
                    lchar = dict[i];
                } else if (lchar != -1) {
                    dict[i] = (char)lchar;
                }
            }

            
            StringBuilder decoded = new StringBuilder((int)@base);
            BigInteger bigBase = @base;
            for (long i = @base - 1; i >= 0; --i) {
                BigInteger pow = BigInteger.Pow(bigBase, (int)i);
                BigInteger div = enc / pow;
                char c = dict[(long)div];
                BigInteger fv = freq[c];
                BigInteger cv = cf[c];
                BigInteger diff = enc - pow * cv;
                enc = diff / fv;
                decoded.Append(c);
            }

            
            return decoded.ToString();
        }

        static void Main(string[] args) {
            long radix = 10;
            string[] strings = { "DABDDB", "DABDDBBDDBA", "ABRACADABRA", "TOBEORNOTTOBEORTOBEORNOT" };
            foreach (string str in strings) {
                Triple encoded = ArithmeticCoding(str, radix);
                string dec = ArithmeticDecoding(encoded.Item1, radix, encoded.Item2, encoded.Item3);
                Console.WriteLine("{0,-25}=> {1,19} * {2}^{3}", str, encoded.Item1, radix, encoded.Item2);
                if (str != dec) {
                    throw new Exception("\tHowever that is incorrect!");
                }
            }
        }
    }
}


Go: package main

import (
    "fmt"
    "math/big"
)

func cumulative_freq(freq map[byte]int64) map[byte]int64 {
    total := int64(0)
    cf := make(map[byte]int64)
    for i := 0; i < 256; i++ {
        b := byte(i)
        if v, ok := freq[b]; ok {
            cf[b] = total
            total += v
        }
    }
    return cf
}

func arithmethic_coding(str string, radix int64) (*big.Int,
                                *big.Int, map[byte]int64) {

    
    chars := []byte(str)

    
    freq := make(map[byte]int64)
    for _, c := range chars {
        freq[c] += 1
    }

    
    cf := cumulative_freq(freq)

    
    base := len(chars)

    
    L := big.NewInt(0)

    
    pf := big.NewInt(1)

    
    
    bigBase := big.NewInt(int64(base))

    for _, c := range chars {
        x := big.NewInt(cf[c])

        L.Mul(L, bigBase)
        L.Add(L, x.Mul(x, pf))
        pf.Mul(pf, big.NewInt(freq[c]))
    }

    
    U := big.NewInt(0)
    U.Set(L)
    U.Add(U, pf)

    bigOne := big.NewInt(1)
    bigZero := big.NewInt(0)
    bigRadix := big.NewInt(radix)

    tmp := big.NewInt(0).Set(pf)
    powr := big.NewInt(0)

    for {
        tmp.Div(tmp, bigRadix)
        if tmp.Cmp(bigZero) == 0 {
            break
        }
        powr.Add(powr, bigOne)
    }

    diff := big.NewInt(0)
    diff.Sub(U, bigOne)
    diff.Div(diff, big.NewInt(0).Exp(bigRadix, powr, nil))

    return diff, powr, freq
}

func arithmethic_decoding(num *big.Int, radix int64,
          pow *big.Int, freq map[byte]int64) string {

    powr := big.NewInt(radix)

    enc := big.NewInt(0).Set(num)
    enc.Mul(enc, powr.Exp(powr, pow, nil))

    base := int64(0)
    for _, v := range freq {
        base += v
    }

    
    cf := cumulative_freq(freq)

    
    dict := make(map[int64]byte)
    for k, v := range cf {
        dict[v] = k
    }

    
    lchar := -1
    for i := int64(0); i < base; i++ {
        if v, ok := dict[i]; ok {
            lchar = int(v)
        } else if lchar != -1 {
            dict[i] = byte(lchar)
        }
    }

    
    decoded := make([]byte, base)
    bigBase := big.NewInt(base)

    for i := base - 1; i >= 0; i-- {

        pow := big.NewInt(0)
        pow.Exp(bigBase, big.NewInt(i), nil)

        div := big.NewInt(0)
        div.Div(enc, pow)

        c := dict[div.Int64()]
        fv := freq[c]
        cv := cf[c]

        prod := big.NewInt(0).Mul(pow, big.NewInt(cv))
        diff := big.NewInt(0).Sub(enc, prod)
        enc.Div(diff, big.NewInt(fv))

        decoded[base-i-1] = c
    }

    
    return string(decoded)
}

func main() {

    var radix = int64(10)

    strSlice := []string{
        `DABDDB`,
        `DABDDBBDDBA`,
        `ABRACADABRA`,
        `TOBEORNOTTOBEORTOBEORNOT`,
    }

    for _, str := range strSlice {
        enc, pow, freq := arithmethic_coding(str, radix)
        dec := arithmethic_decoding(enc, radix, pow, freq)
        fmt.Printf("%-25s=> %19s * %d^%s\n", str, enc, radix, pow)

        if str != dec {
            panic("\tHowever that is incorrect!")
        }
    }
}