Arithmetic coding/As a generalized change of radix: Difference between revisions
Content added Content deleted
(Added c#) |
|||
Line 13: | Line 13: | ||
Verify the implementation by decoding the results back into strings and checking for equality with the given strings. |
Verify the implementation by decoding the results back into strings and checking for equality with the given strings. |
||
=={{header|C#|C sharp}}== |
|||
{{trans|Java}} |
|||
<lang csharp>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) { |
|||
// The frequency of characters |
|||
Freq freq = new Freq(); |
|||
foreach (char c in str) { |
|||
if (freq.ContainsKey(c)) { |
|||
freq[c] += 1; |
|||
} else { |
|||
freq[c] = 1; |
|||
} |
|||
} |
|||
// The cumulative frequency |
|||
Freq cf = CumulativeFreq(freq); |
|||
// Base |
|||
BigInteger @base = str.Length; |
|||
// Lower bound |
|||
BigInteger lower = 0; |
|||
// Product of all frequencies |
|||
BigInteger pf = 1; |
|||
// Each term is multiplied by the product of the |
|||
// frequencies of all previously occuring symbols |
|||
foreach (char c in str) { |
|||
BigInteger x = cf[c]; |
|||
lower = lower * @base + x * pf; |
|||
pf = pf * freq[c]; |
|||
} |
|||
// Upper bound |
|||
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(); |
|||
// Create the cumulative frequency table |
|||
Freq cf = CumulativeFreq(freq); |
|||
// Create the dictionary |
|||
Dictionary<long, char> dict = new Dictionary<long, char>(); |
|||
foreach (char key in cf.Keys) { |
|||
long value = cf[key]; |
|||
dict[value] = key; |
|||
} |
|||
// Fill the gaps in the dictionary |
|||
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; |
|||
} |
|||
} |
|||
// Decode the input number |
|||
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 the decoded output |
|||
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!"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}</lang> |
|||
{{out}} |
|||
<pre>DABDDB => 251 * 10^2 |
|||
DABDDBBDDBA => 167351 * 10^6 |
|||
ABRACADABRA => 7954170 * 10^4 |
|||
TOBEORNOTTOBEORTOBEORNOT => 1150764267498783364 * 10^15</pre> |
|||
=={{header|D}}== |
=={{header|D}}== |