如何压缩仅包含 "F" 和 "G" 的 256 字节字符串?

How would you compress 256-byte string consists of only "F" and "G"?

理论上,您可以将这个仅包含 "F" 和 "G" 的 256 字节字符串压缩多少?

FGFFFFFFGFFFFGGGGGGGGGGGGGFFFFFGGGGGGGGGGGGFFGFGGGFFFGGGGGGGGFFFFFFFFFFFFFFFFFFFFFGGGGGGFFFGFGGFGFFFFGFFGFGGFFFGFGGFGFFFGFGGGGFGGGGGGGGGFFFFFFFFGGGGGGGFFFFFGFFGGGGGGGFFFGGGFFGGGGGGFFGGGGGGGGGFFGFFGFGFFGFFGFFFFGGGGFGGFGGGFFFGGGFFFGGGFFGGFFGGGGFFGFGGFFFGFGGF

虽然我没有看到真实世界的应用程序,但有趣的是 gz、bzip2 和 deflate 等压缩算法在这种情况下有一个缺点。
好吧,我有这个答案和要演示的 C# 代码:

using System;

public class Program
{
    public static void Main()
    {
        string testCase = "FGFFFFFFGFFFFGGGGGGGGGGGGGFFFFFGGGGGGGGGGGGFFGFGGGFFFGGGGGGGGFFFFFFFFFFFFFFFFFFFFFGGGGGGFFFGFGGFGFFFFGFFGFGGFFFGFGGFGFFFGFGGGGFGGGGGGGGGFFFFFFFFGGGGGGGFFFFFGFFGGGGGGGFFFGGGFFGGGGGGFFGGGGGGGGGFFGFFGFGFFGFFGFFFFGGGGFGGFGGGFFFGGGFFFGGGFFGGFFGGGGFFGFGGFFFGFGGF";
        uint[] G = new uint[8]; // 256 bit

        for (int i = 0; i < testCase.Length; i++)
            G[(i / 32)] += (uint)(((testCase[i] & 1)) << (i % 32));

        for (int i = 0; i < 8; i++)
            Console.WriteLine(G[i]);

        string gTestCase = string.Empty;

        //G 71  0100 0111
        //F 70  0100 0110
        for (int i = 0; i < 256; i++)
            gTestCase += (char)((((uint)G[i / 32] & (1 << (i % 32))) >> (i % 32)) | 70);

        Console.WriteLine(testCase);
        Console.WriteLine(gTestCase);

        if (testCase == gTestCase)
            Console.WriteLine("OK.");
    }
}

听起来可能很傻,但至于我如何改进算法,使这个256位的十进制数可以进一步压缩,我有以下想法:
(注:以下是不同的讨论主题,但与进一步压缩256字节有关)

根据我对微软实现Decimal

的理解

96-bit + 96-bit = 128-bit decimal.

这意味着包含任意两个不同字符的 192 字节字符串可以编码为 128 位数字而不是 192 位数字。正确吗?

我的问题是:

  1. 我可以用 256 字节的字符串做同样的事情吗?
    (通过将它们中的每一个分成一对两个数字,然后将这两个数字相加为 Decimal 短于 256 位)?

  2. 如何将上述128位Decimal解码回一对两个96位数字,同时保持压缩数据大小小于 192 位?

抱歉我之前的问题比较含糊。

以下代码将演示如何将两个 96 个字符的 "binary" 字符串添加为 128 个字符的二进制字符串。

public static string AddBinary(string a, string b) // 96-char binary strings
{
    int[] x = { 0, 0, 0 };
    int[] y = { 0, 0, 0 };

    string c = String.Empty;

    for (int z = 0; z < a.Length; z++)
        x[(z / 32)] |= ((byte)(a[a.Length - z - 1]) & 1) << (z % 32);
    for (int z = 0; z < b.Length; z++)
        y[(z / 32)] |= ((byte)(b[b.Length - z - 1]) & 1) << (z % 32);

    decimal m = new decimal(x[0], x[1], x[2], false, 0); //96-bit
    decimal n = new decimal(y[0], y[1], y[2], false, 0); //96-bit
    decimal k = decimal.Add(m, n);
    int[] l = decimal.GetBits(k); //128-bit      

    Console.WriteLine(k);

    for (int z = 127; z >= 0; z--)
        c += (char)(((l[(z / 32)] & (1 << (z % 32))) >> (z % 32)) | 48);

    return c.Contains("1") ? c.TrimStart('0') : "0";
}

96-bit + 96-bit = 128-bit decimal.

这是误会。 Decimal是96bit的integer/mantissa,一个符号和一个0到28(~5bit)的指数构成比例因子尾数。
加法是从2×(1+5+96)位到1×(1+5+96)位,包括不可避免的舍入误差和溢出。

您不能轻易地从求和中得到加数 - 对于初学者来说,加法是对称的,没有任何地球上的方法可以知道两个加数中哪个是第一个,哪个是第二个。

mentioned the programmer's variant of compressibility: Kolmogorov complexity.
平心而论,您必须将输入字符串的 重新编码 的 256 位添加程序的大小,才能将这些位转换为原始字符串。
(与 gz、bzip2、deflate(、LZW) - decoders for "pure LZ" can be very small. The usual escape is to define a file format 一样,包括可识别的 header。)

mentioned one consequence of the Pigeon-hole principle:要区分每一个192位的组合,你需要不少于2^192个代码。