代码之家  ›  专栏  ›  技术社区  ›  Joe

我能用任何字节数组(scala)构造一个bigint吗?

  •  0
  • Joe  · 技术社区  · 15 年前

    我试图用尽可能短的字符串表示MD5哈希的结果。把它变成一个十六进制字符串,让G到Z变成废物,这似乎是一种浪费。

    我的一个想法是将输入的MD5哈希作为一个字节数组,并构造一个 BigInt 带着它。我可以打电话 toString(36) ,并在字符串中以36为基数获取数字( -?[0-9a-z]* ,数字可以是正数或负数)。它对我有用。

    问题是,我不确定 大整数 可以用任何字节数组构造,我无法用测试来证明它(至少不是及时的!)我想是的,因为我知道bigint可以是任意大小的。我不能使用这个方法,除非我确定它对所有可能的输出都有效。所以,有人能告诉我它是否适用于所有的输入(或者如何轻松地转换一个字节数组,以便用基36表示)。

    澄清 :我有这个实现,我在询问整个域的行为(即000000000000000000000000000000000到ffffffffffffffffffffffffffffffffffffffffffff)

    2 回复  |  直到 15 年前
        1
  •  3
  •   Mitch Blevins    15 年前

    根据上面的反馈,以下实现将可靠地对任意字节数组进行编码/解码:

    package blevins.example
    
    object BigIntEncoder {
      val radix = 36
    
      implicit def byteArrayToString(ba: Array[Byte]): String = {
        new java.math.BigInteger(addByte(ba)).toString(radix)
      }
    
      implicit def stringToByteArray(s: String): Array[Byte] = {
        stripByte(new java.math.BigInteger(s, radix).toByteArray)
      }
    
      def addByte(ba: Array[Byte]): Array[Byte] = {
        val h = new Array[Byte](1)
        h(0) = 0x01
        h ++ ba
      }
    
      def stripByte(ba: Array[Byte]): Array[Byte] = {
        ba.slice(1,ba.size)
      }
    
    }
    

    请注意,我们正在向数组的头部添加一个额外的0x01字节,以避免从字节数组的两个补码中得到任何副作用。

    编辑:证明这一点的相关测试记录如下: http://cleverlytitled.blogspot.com/2009/10/scalacheck.html

        2
  •  0
  •   Mitch Blevins    15 年前

    base64编码不会比base36短吗?您可以在周围找到许多实现。

    但是,要真正回答这个问题:

      // Make a big randomly-filled byte array
      val random = scala.util.Random
      val arraySize = 8543
      val bytes: Array[Byte] = new Array[Byte](arraySize) // make some big array
      random.nextBytes(bytes) // fill it randomly
    
      // Make a BigInt out of it and the corresponding base36 string representation
      val bi: BigInt = new BigInt(new java.math.BigInteger(bytes))
      val strRep: String = bi.toString(36)
    
      // Make a new BigInt out of the string rep.  Does it match?
      val bi2: BigInt = new BigInt(new java.math.BigInteger(strRep, 36))
      if (bi == bi2) {
          println("yippee!!")
      }
    
      // Make a new byte array out of the BigInt.  Does it match the original array?
      val bytes2: Array[Byte] = bi2.toByteArray
      if (bytes deepEquals bytes2) {
          println("yippee again!!")
      }