【问题标题】:Most efficient way to store and retrieve a 512-bit number?存储和检索 512 位数字的最有效方法是什么?
【发布时间】:2014-05-14 07:49:32
【问题描述】:

我有一个 512 个字符的字符串,其中仅包含 0、1。我试图将其表示为可以节省空间的数据结构。 BitArray 是最有效的方式吗?

我也在考虑使用 16 int32 来存储数字,那么它将是 16 * 4 = 64 字节。

【问题讨论】:

  • 为什么不把它解析成BigInteger

标签: c# bitarray


【解决方案1】:

最有效的方法是拥有八个 UInt64/ulongInt64/long 类型变量(或单个数组),尽管这对于查询/设置可能不是最佳的。实际上,解决此问题的一种方法是使用BitArray(它基本上是前一种方法的包装,包括额外的开销[1])。无论是方便使用还是高效存储都是一个选择问题。

如果这还不够,您始终可以选择应用压缩,例如 RLE 编码或各种其他广泛可用的编码方法(gzip/bzip/等...)。不过,这将需要额外的处理能力。

这取决于你对高效的定义。

[1] 额外的开销,如存储开销。 BitArray 在内部使用Int32-array 来存储值。除此之外,BitArray 还存储其当前的变异版本、“分配”的整数数量和一个同步根。即使少量值的开销可以忽略不计,但如果您将大量这些值保留在内存中,这可能会成为问题。

【讨论】:

  • 您能否详细说明BitArray 要求的“额外开销”?您的意思是 BitArray 需要更多内存或存储空间吗?或者操作 BitArray 比使用 long[] 做同样的事情要慢?
  • 将此添加到答案中。
【解决方案2】:

使用 .NET 中的 BigInteger。它可以轻松支持 512 位数字以及对这些数字的操作。

BigInteger.Parse("your huge number");

【讨论】:

    【解决方案3】:

    BitArray(512 位)、byte[64]int[16]long[8](或List<> 的变体)或BigInteger 都将比您的String 高效得多。我想说byte[] 通常是表示此类数据的最惯用/典型的方式。例如,ComputeHash 使用byte[]Streams 处理byte[]s,如果将此数据作为BLOB 存储在数据库中,byte[] 将是处理该数据的最自然方式。因此,使用它可能是有意义的。

    另一方面,如果此数据代表一个数字,您可能会做一些像加法和减法一样的数字运算,您可能希望使用BigInteger

    这些方法的性能大致相同,因此您应该主要根据诸如有意义之类的因素来选择它们,然后再根据您的使用情况进行基准测试。

    【讨论】:

      【解决方案4】:

      最高效可能意味着许多不同的事情......

      1. 从内存管理的角度来看效率最高?
      2. 从 CPU 计算的角度来看效率最高?
      3. 从使用角度来看最有效? (关于编写使用数字进行计算的代码)

      对于 1 - 使用 byte[64]long[8] - 如果您不进行计算或不介意编写自己的计算。

      对于 3 绝对是 BigInteger 是要走的路。您已经定义了数学函数,只需将二进制数转换为十进制表示。

      编辑:听起来你不想要 BigInteger 由于大小问题......但我认为你会发现你当然必须将其解析为可枚举/产量组合您一次解析一点,而不是同时将整个数据结构保存在内存中。

      话虽如此...我可以帮助您将字符串解析为 Int64 的数组...感谢 King King 提供此 linq 语句的一部分 here

      // convert string into an array of int64's
      // Note that MSB is in result[0]
      var result = input.Select((x, i) => i)
                      .Where(i => i % 64 == 0)
                      .Select(i => input.Substring(i, input.Length - i >= 64 ? 
                          64 : input.Length - i))
                      .Select(x => Convert.ToUInt64(x, 2))
                      .ToArray();          
      

      如果您决定想要一个不同的数组结构byte[64] 或任何应该易于修改的东西。

      编辑 2: 好吧,我觉得无聊,所以我写了一个 EditDifference 函数来取乐……给你……

      static public int GetEditDistance(ulong[] first, ulong[] second)
      {
          int editDifference = 0;
          var smallestArraySize = Math.Min(first.Length, second.Length);
          for (var i = 0; i < smallestArraySize; i++)
          {
              long signedDifference;
              var f = first[i];
              var s = second[i];
              var biggest = Math.Max(f, s);
              var smallest = Math.Min(f, s);
              var difference = biggest - smallest;
              if (difference > long.MaxValue)
              {
                  editDifference += 1;
                  signedDifference = Convert.ToInt64(difference - long.MaxValue - 1);
              }
              else
                  signedDifference = Convert.ToInt64(difference);
              editDifference += Convert.ToString(signedDifference, 2)
                  .Count(x => x == '1');
          }
          // if arrays are different sizes every bit is considered to be different
          var differenceOfArraySize = 
              Math.Max(first.Length, second.Length) - smallestArraySize;
          if (differenceOfArraySize > 0)
              editDifference += differenceOfArraySize * 64;
          return editDifference;
      }
      

      【讨论】:

      • 计算对我来说很重要。我想计算两个数字之间的编辑距离。此外,我得到了大约 1 亿个这些数字,因此文件的大小也很重要。 1 亿 * 64 字节 ~ 6GB
      • 对于两个0、1的二进制字符串,可能只是它们彼此不同的位数。
      • @Yang 我的回答有帮助吗?你认为这是答案吗?
      猜你喜欢
      • 1970-01-01
      • 2021-09-05
      • 2012-04-17
      • 2017-01-12
      • 2017-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-03
      相关资源
      最近更新 更多